├── .gitignore ├── lesson-1 ├── .gitignore ├── README.md ├── index.html ├── node start │ ├── index.js │ └── server │ │ └── bin.js ├── node-CommonJS-module │ ├── .gitignore │ ├── date │ │ ├── getCurrentMonth.js │ │ ├── index.js │ │ └── isLeapYear.js │ ├── index.js │ ├── package.json │ └── users.js ├── node-module-es6-mjs │ ├── .gitignore │ ├── index.mjs │ ├── package.json │ └── users.mjs ├── node-module-es6-type │ ├── .gitignore │ ├── index.js │ ├── package.json │ └── users.js ├── npm-example │ ├── .gitignore │ ├── index.js │ └── package.json └── slides │ ├── JS-V8-setTimeout-work.jpg │ ├── JS-V8-work.jpg │ ├── Nodejs-structure.jpg │ ├── motivation-picture.png │ ├── npm-structure.jpg │ ├── project-create-steps.jpg │ └── reasons-learn-nodejs.jpg ├── lesson-10 ├── index.html ├── pagination-mongoose │ ├── .env │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── controllers │ │ ├── index.js │ │ └── products.js │ ├── helpers │ │ ├── index.js │ │ └── sendSuccessRes.js │ ├── middlewares │ │ ├── controllerWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ └── product.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ └── routes │ │ └── api │ │ └── products.js ├── slides │ ├── QA-work.jpg │ ├── Test-driven-development-ru.png │ ├── developing-with-test.jpg │ ├── piramida.drawio.png │ ├── test-first-schema.jpg │ ├── test-instruments.png │ └── test-schema.jpg └── test-function-example │ ├── app.js │ ├── funcs │ ├── index.js │ ├── isLeapYear.js │ └── isLearYear.test.js │ ├── index.html │ └── package.json ├── lesson-11 ├── auth-example │ ├── .env.example │ ├── .gitignore │ ├── app.js │ ├── controllers │ │ ├── auth │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── logout.js │ │ │ ├── register.js │ │ │ └── verify.js │ │ ├── index.js │ │ └── orders │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getAllByUser.js │ │ │ └── index.js │ ├── helpers │ │ ├── index.js │ │ ├── sendEmail.js │ │ └── sendSuccessRes.js │ ├── middlewares │ │ ├── authenticate.js │ │ ├── controllerWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ ├── order.js │ │ └── user.js │ ├── package.json │ └── routes │ │ └── api │ │ ├── auth.js │ │ └── orders.js ├── index.html ├── nodemailer-meta-ua │ ├── .gitignore │ ├── app.js │ ├── helpers │ │ └── sendEmail.js │ └── package.json ├── nodemailer │ ├── .gitignore │ ├── app.js │ ├── helpers │ │ └── sendEmail.js │ └── package.json ├── sendgrid │ ├── .gitignore │ ├── app.js │ ├── helpers │ │ └── sendEmail.js │ └── package.json └── slides │ ├── mailing-schema.jpg │ ├── nodemailer.jpg │ └── sendgrid-schema.jpg ├── lesson-12 ├── README.md ├── index.html ├── mongodb-project │ ├── .env.example │ ├── .gitignore │ ├── app.js │ ├── controllers │ │ ├── index.js │ │ └── products.js │ ├── helpers │ │ ├── index.js │ │ └── sendSuccessReq.js │ ├── middlewares │ │ ├── controllerWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── category.js │ │ ├── index.js │ │ └── product.js │ ├── package.json │ └── routes │ │ └── api │ │ └── products.js ├── slides │ ├── different-between-websockets-and-http.jpg │ ├── web-socket-client-server-schema.jpg │ ├── web-socket-personal-client-object.jpg │ ├── websocket-main-features.jpg │ └── websocket-projects.jpg ├── web-socket-chat-example │ ├── .gitignore │ ├── app.js │ ├── frontend │ │ ├── index.html │ │ └── style.css │ └── package.json └── websocket-basic-example │ ├── .gitignore │ ├── app.js │ ├── frontend.html │ └── package.json ├── lesson-13 ├── index.html ├── mongodb-project │ ├── .env.example │ ├── .gitignore │ ├── Dockerfile │ ├── app.js │ ├── controllers │ │ ├── index.js │ │ └── products.js │ ├── helpers │ │ ├── index.js │ │ └── sendSuccessReq.js │ ├── middlewares │ │ ├── controllerWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── category.js │ │ ├── index.js │ │ └── product.js │ ├── package.json │ └── routes │ │ └── api │ │ └── products.js ├── php-project │ ├── Dockerfile │ └── index.php └── slides │ ├── 05efe6379b.jpg │ ├── 09bf934cc1.jpg │ ├── 0aac227e26.jpg │ ├── 1e8868fd69.jpg │ ├── 206360c857.jpg │ ├── 35e71d29de.jpg │ ├── 505114e755.jpg │ ├── 6423d760db.jpg │ ├── 7155b6b76d.jpg │ ├── 76a678f8e7.jpg │ ├── 83fc82807e.jpg │ ├── 9b35bf3889.jpg │ ├── a7cc498c22.jpg │ ├── b78636dee9.jpg │ ├── ca8261d313.jpg │ └── daf8a4de74.jpg ├── lesson-2 ├── README.md ├── file-reader │ ├── .gitignore │ ├── files │ │ └── read.txt │ ├── index.js │ ├── package.json │ └── promise-index.js ├── slides │ └── work-with-files-examples.jpg ├── work-with-files │ ├── .gitignore │ ├── app.js │ └── package.json ├── work-with-json-files-example-2 │ ├── .gitignore │ ├── app.js │ ├── package.json │ └── products │ │ ├── add.js │ │ ├── getAll.js │ │ ├── getById.js │ │ ├── index.js │ │ ├── products.json │ │ ├── removeById.js │ │ ├── updateById.js │ │ └── updateProducts.js └── work-with-json-files │ ├── .gitignore │ ├── app.js │ ├── package.json │ └── products │ ├── add.js │ ├── getAll.js │ ├── getById.js │ ├── index.js │ ├── products.json │ ├── removeById.js │ ├── updateById.js │ └── updateProducts.js ├── lesson-3 ├── .gitignore ├── README.md ├── express-example-1 │ ├── .gitignore │ ├── app.js │ └── package.json ├── express-example-2 │ ├── .gitignore │ ├── app.js │ ├── package.json │ └── products.js ├── express-example-3 │ ├── .gitignore │ ├── app.js │ ├── index.html │ ├── package.json │ ├── products.js │ └── server.log ├── http-server-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── index.html └── slides │ ├── Client-Server-schema.jpg │ ├── fullstack-developer-cors-problem-2.jpg │ ├── fullstack-developer-cors-problem.jpg │ ├── middleware-work-schema-details-2.jpg │ ├── middleware-work-schema-details-3.jpg │ ├── middleware-work-schema-details.jpg │ ├── middleware-work-schema.jpg │ └── what-is-it-cors.jpg ├── lesson-4 ├── README.md ├── index.html ├── joi-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── nodejs-homework-template-master-2 │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── controllers │ │ ├── index.js │ │ └── products.js │ ├── helpers │ │ ├── index.js │ │ └── sendSuccessRes.js │ ├── middlewares │ │ ├── controllerWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── model │ │ └── products │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getById.js │ │ │ ├── index.js │ │ │ ├── products.json │ │ │ ├── removeById.js │ │ │ ├── updateById.js │ │ │ └── updateProducts.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ ├── routes │ │ └── api │ │ │ └── products.js │ └── schemas │ │ ├── index.js │ │ └── product.js ├── nodejs-homework-template-master │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── model │ │ └── products │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getById.js │ │ │ ├── index.js │ │ │ ├── products.json │ │ │ ├── removeById.js │ │ │ ├── updateById.js │ │ │ └── updateProducts.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ ├── routes │ │ └── api │ │ │ └── products.js │ └── schemas │ │ ├── index.js │ │ └── product.js └── slides │ ├── CRUD.jpg │ ├── Client-Server-schema.jpg │ ├── HTTP-methods.jpg │ ├── REST-API-additional-rules.jpg │ ├── REST-API-basic-rules.jpg │ ├── Server-response-code.jpg │ ├── middleware-work-schema-details-2.jpg │ ├── middleware-work-schema-details-3.jpg │ ├── middleware-work-schema-details.jpg │ ├── middleware-work-schema.jpg │ ├── old-routes-example.jpg │ └── what-is-it-cors.jpg ├── lesson-5 ├── index.html ├── mongodb-project │ ├── .gitignore │ ├── app.js │ ├── models │ │ ├── category.js │ │ └── index.js │ └── package.json ├── process-env-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── readme.md └── slides │ ├── backend-structure.jpg │ ├── database-types.jpg │ ├── documents-database-schema.jpg │ ├── dotenv-work-schema.jpg │ ├── mongodb-database-structure.jpg │ ├── remote-database.jpg │ ├── schema-model-collection.jpg │ └── schema-model-example.jpg ├── lesson-6 ├── index.html ├── mongodb-project │ ├── .gitignore │ ├── app.js │ ├── models │ │ ├── category.js │ │ └── index.js │ └── package.json ├── nodejs-homework-template-master │ ├── .env │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── controllers │ │ ├── index.js │ │ └── products.js │ ├── helpers │ │ ├── index.js │ │ └── sendSuccessRes.js │ ├── middlewares │ │ ├── controllerWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ └── product.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ └── routes │ │ └── api │ │ └── products.js └── slides │ ├── schema-model-collection.jpg │ └── schema-model-example.jpg ├── lesson-7 ├── .gitignore ├── README.md ├── auth-example │ ├── .env.example │ ├── .gitignore │ ├── app.js │ ├── controllers │ │ ├── auth │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── logout.js │ │ │ └── register.js │ │ └── index.js │ ├── helpers │ │ ├── index.js │ │ └── sendSuccessRes.js │ ├── models │ │ ├── index.js │ │ └── user.js │ ├── package.json │ └── routes │ │ └── api │ │ └── auth.js ├── hash-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── index.html └── slides │ ├── HTTP-common-schema.jpg │ ├── HTTP-personal-request-schema.jpg │ ├── frontend-backend-requests-with-token.jpg │ ├── hash-schema.jpg │ ├── jwt-token-real-life-example.jpg │ ├── process.env-and-deploy.jpg │ ├── register-auth-steps.jpg │ └── reigster-auth-create-steps.jpg ├── lesson-8 ├── .gitignore ├── README.md ├── auth-example │ ├── .env.example │ ├── .gitignore │ ├── app.js │ ├── controllers │ │ ├── auth │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── logout.js │ │ │ └── register.js │ │ ├── index.js │ │ └── orders │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getAllByUser.js │ │ │ └── index.js │ ├── helpers │ │ ├── index.js │ │ └── sendSuccessRes.js │ ├── middlewares │ │ ├── authenticate.js │ │ ├── controllerWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ ├── order.js │ │ └── user.js │ ├── package.json │ └── routes │ │ └── api │ │ ├── auth.js │ │ └── orders.js ├── index.html ├── jsonwebtoken-example │ ├── .gitignore │ ├── app.js │ └── package.json └── slides │ ├── JWT-token-schema.jpg │ ├── hash-schema.jpg │ └── logout-examples.jpg └── lesson-9 ├── README.md ├── index.html ├── multer-example-2 ├── .env ├── .gitignore ├── app.js ├── controllers │ ├── index.js │ └── products.js ├── index.html ├── middlewares │ ├── controllerWrapper.js │ ├── index.js │ └── upload.js ├── models │ ├── index.js │ └── product.js ├── package.json └── routes │ └── api │ └── products.js ├── multer-example ├── .gitignore ├── app.js ├── frontend.html ├── index.html ├── package.json ├── public │ └── products │ │ └── 2085-1.png └── temp │ └── .gitkeep └── slides └── multer-work-schema.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-1/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-1/README.md: -------------------------------------------------------------------------------- 1 | [Мотивационная картинка](./slides/motivation-picture.png) 2 | 3 | [Причины изучать Node.js](./slides/reasons-learn-nodejs.jpg) 4 | 5 | [Как V8 обрабатывает JS-код](./slides/JS-V8-work.jpg) 6 | 7 | [Как V8 обрабатывает JS-код, которого нет в документации JS](./slides/JS-V8-setTimeout-work.jpg) 8 | 9 | [Структура Node.js](./slides/Nodejs-structure.jpg) 10 | 11 | [Структура NPM](./slides/npm-structure.jpg) 12 | 13 | [Последовательность шагов при создании проекта](./slides/project-create-steps.jpg) 14 | -------------------------------------------------------------------------------- /lesson-1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /lesson-1/node start/index.js: -------------------------------------------------------------------------------- 1 | const date = new Date(); 2 | 3 | // console.log(date.getFullYear()); 4 | console.log("Welcome to Hell!"); -------------------------------------------------------------------------------- /lesson-1/node start/server/bin.js: -------------------------------------------------------------------------------- 1 | console.log("Вложенный файл"); -------------------------------------------------------------------------------- /lesson-1/node-CommonJS-module/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-1/node-CommonJS-module/date/getCurrentMonth.js: -------------------------------------------------------------------------------- 1 | const getCurrentMonth = ()=> { 2 | const now = new Date(); 3 | return now.getMonth() + 1; 4 | } 5 | 6 | module.exports = getCurrentMonth; 7 | 8 | -------------------------------------------------------------------------------- /lesson-1/node-CommonJS-module/date/index.js: -------------------------------------------------------------------------------- 1 | const getCurrentMonth = require("./getCurrentMonth"); 2 | const isLeapYear = require("./isLeapYear"); 3 | 4 | module.exports = { 5 | getCurrentMonth, 6 | isLeapYear 7 | } 8 | 9 | -------------------------------------------------------------------------------- /lesson-1/node-CommonJS-module/date/isLeapYear.js: -------------------------------------------------------------------------------- 1 | const isLeapYear = (year) => { 2 | 3 | } 4 | 5 | module.exports = isLeapYear; -------------------------------------------------------------------------------- /lesson-1/node-CommonJS-module/index.js: -------------------------------------------------------------------------------- 1 | // const nodemon = require("nodemon"); 2 | // const users = require("./users"); 3 | 4 | // console.log(users); 5 | 6 | // const obj = require("./users"); 7 | 8 | // console.log(obj); 9 | 10 | // const {clients} = require("./users"); 11 | 12 | // console.log(clients); 13 | 14 | // const dateFunctions = require("./date"); 15 | // const {getCurrentMonth} = require("./date"); 16 | // const getCurrentMonth = require("./date/getCurrentMonth") 17 | 18 | // const {getCurrentMonth} = require("./date"); 19 | 20 | // console.log(`Текущий месяц - ${getCurrentMonth()}`) 21 | 22 | const currentMonth = require("./date/getCurrentMonth")(); 23 | 24 | console.log(`Текущий месяц - ${currentMonth}`); 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /lesson-1/node-CommonJS-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-CommonJS-module", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index", 9 | "start:dev": "nodemon index" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lesson-1/node-CommonJS-module/users.js: -------------------------------------------------------------------------------- 1 | // const now = new Date(); 2 | // console.log(now); 3 | 4 | const admins = ["Alex", "Andrey", "VAsiliy"]; 5 | 6 | const clients = ["Anna", "Alina", "Tamara"]; 7 | 8 | const users = { 9 | admins, 10 | clients 11 | }; 12 | 13 | module.exports = users; 14 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-mjs/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-1/node-module-es6-mjs/index.mjs: -------------------------------------------------------------------------------- 1 | import users from "./users.mjs"; 2 | import {clients} from "./users.mjs"; 3 | 4 | console.log(users); 5 | console.log(clients); 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-mjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-module-es6-mjs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index", 9 | "start:dev": "nodemon index" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-mjs/users.mjs: -------------------------------------------------------------------------------- 1 | // const now = new Date(); 2 | // console.log(now); 3 | 4 | export const admins = ["Alex", "Andrey", "VAsiliy"]; 5 | 6 | export const clients = ["Anna", "Alina", "Tamara"]; 7 | 8 | const users = { 9 | admins, 10 | clients 11 | }; 12 | 13 | export default users; 14 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-type/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-1/node-module-es6-type/index.js: -------------------------------------------------------------------------------- 1 | import users from "./users.js"; 2 | 3 | console.log(users); 4 | 5 | 6 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-type/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-module-es6-type", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start": "node index", 10 | "start:dev": "nodemon index" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "nodemon": "^2.0.12" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-type/users.js: -------------------------------------------------------------------------------- 1 | export const admins = ["Alex", "Andrey", "VAsiliy"]; 2 | 3 | export const clients = ["Anna", "Alina", "Tamara"]; 4 | 5 | const users = { 6 | admins, 7 | clients 8 | }; 9 | 10 | export default users; 11 | -------------------------------------------------------------------------------- /lesson-1/npm-example/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules/ -------------------------------------------------------------------------------- /lesson-1/npm-example/index.js: -------------------------------------------------------------------------------- 1 | console.log("Welcome, friends!"); -------------------------------------------------------------------------------- /lesson-1/npm-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index", 9 | "start:dev": "nodemon index" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "cors": "^2.8.5", 16 | "dotenv": "^10.0.0", 17 | "express": "^4.17.1", 18 | "mongoose": "^6.0.5", 19 | "nodemailer": "^6.6.3", 20 | "slick-slider": "^1.8.2" 21 | }, 22 | "devDependencies": { 23 | "nodemon": "^2.0.12", 24 | "webpack": "^5.52.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lesson-1/slides/JS-V8-setTimeout-work.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-1/slides/JS-V8-setTimeout-work.jpg -------------------------------------------------------------------------------- /lesson-1/slides/JS-V8-work.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-1/slides/JS-V8-work.jpg -------------------------------------------------------------------------------- /lesson-1/slides/Nodejs-structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-1/slides/Nodejs-structure.jpg -------------------------------------------------------------------------------- /lesson-1/slides/motivation-picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-1/slides/motivation-picture.png -------------------------------------------------------------------------------- /lesson-1/slides/npm-structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-1/slides/npm-structure.jpg -------------------------------------------------------------------------------- /lesson-1/slides/project-create-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-1/slides/project-create-steps.jpg -------------------------------------------------------------------------------- /lesson-1/slides/reasons-learn-nodejs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-1/slides/reasons-learn-nodejs.jpg -------------------------------------------------------------------------------- /lesson-10/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | 12 | 13 |
14 | 24 | 25 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.fbkoo.mongodb.net/online_shop?retryWrites=true&w=majority -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: ['standard'], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | }, 11 | rules: { 12 | 'comma-dangle': 'off', 13 | 'space-before-function-paren': 'off', 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vcode 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | 5 | const productsRouter = require('./routes/api/products') 6 | 7 | const app = express() 8 | 9 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 10 | 11 | // app.use(logger(formatsLogger)) 12 | app.use(cors()) 13 | app.use(express.json()) 14 | 15 | app.use('/api/products', productsRouter); 16 | 17 | // api/product 18 | app.use((req, res) => { 19 | res.status(404).json({ 20 | status: "error", 21 | message: 'Not found' 22 | }) 23 | }) 24 | 25 | app.use((err, req, res, next) => { 26 | const {status = 500, message = "Server error"} = err; 27 | res.status(status).json({ message }) 28 | }); 29 | 30 | module.exports = app 31 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/bin/server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | require("dotenv").config(); 3 | 4 | const app = require('../app'); 5 | 6 | const {DB_HOST, PORT = 3000} = process.env; 7 | 8 | mongoose.connect(DB_HOST, { 9 | useNewUrlParser: true, 10 | useUnifiedTopology: true 11 | }) 12 | .then(()=> app.listen(PORT)) 13 | .catch(error => { 14 | console.log(error.message); 15 | process.exit(1); 16 | }) 17 | 18 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | 3 | module.exports = { 4 | products 5 | } -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = require("./sendSuccessRes"); 2 | 3 | module.exports = { 4 | sendSuccessRes 5 | } -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/helpers/sendSuccessRes.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = (res, data, status = 200)=> { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | } 8 | 9 | module.exports = sendSuccessRes -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl) => { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch(error){ 7 | next(error); 8 | } 9 | } 10 | }; 11 | 12 | module.exports = controllerWrapper -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = require("./controllerWrapper"); 2 | const validation = require("./validation"); 3 | 4 | module.exports = { 5 | controllerWrapper, 6 | validation 7 | } -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema) => { 2 | return async(req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | res.status(400).json({ 6 | status: "error", 7 | code: 400, 8 | message: error.message 9 | }); 10 | return; 11 | } 12 | next(); 13 | } 14 | }; 15 | 16 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | 3 | module.exports = { 4 | Product 5 | } -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/models/product.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | 4 | const codeRegexp = /^[0-9]{9}$/; // newRegexp("^[0-9]{9}$") 5 | 6 | const productSchema = Schema({ 7 | name: { 8 | type: String, 9 | required: [true, "Название товара обязательно"] 10 | }, 11 | price: { 12 | type: Number, 13 | required: [true, "Цена товара обязательно"], 14 | min: 0.01 15 | }, 16 | code: { 17 | type: String, 18 | unique: true, 19 | match: codeRegexp 20 | }, 21 | active: { 22 | type: Boolean, 23 | default: true 24 | } 25 | }, {versionKey: false, timestamps: true}); 26 | 27 | const joiSchema = Joi.object({ 28 | name: Joi.string().required(), 29 | price:Joi.number().min(0.01).required(), 30 | code: Joi.string().pattern(codeRegexp).required(), 31 | active: Joi.boolean() 32 | }); 33 | 34 | const updateActiveJoiSchema = Joi.object({ 35 | active: Joi.boolean().required() 36 | }); 37 | 38 | const Product = model("product", productSchema); 39 | 40 | module.exports = { 41 | joiSchema, 42 | updateActiveJoiSchema, 43 | Product 44 | }; -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template-2", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "cross-env NODE_ENV=production node ./bin/server.js", 7 | "start:dev": "cross-env NODE_ENV=development nodemon ./bin/server.js", 8 | "lint": "eslint **/*.js", 9 | "lint:fix": "eslint --fix **/*.js" 10 | }, 11 | "dependencies": { 12 | "cors": "2.8.5", 13 | "cross-env": "7.0.3", 14 | "dotenv": "^10.0.0", 15 | "express": "4.17.1", 16 | "http-errors": "^1.8.0", 17 | "joi": "^17.4.2", 18 | "mongoose": "^6.0.7", 19 | "morgan": "1.10.0" 20 | }, 21 | "devDependencies": { 22 | "eslint": "^7.19.0", 23 | "eslint-config-standard": "^16.0.2", 24 | "eslint-plugin-import": "^2.22.1", 25 | "eslint-plugin-node": "^11.1.0", 26 | "eslint-plugin-promise": "^4.2.1", 27 | "nodemon": "2.0.7" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/readme.md: -------------------------------------------------------------------------------- 1 | ## GoIT Node.js Course Template Homework 2 | 3 | Выполните форк этого репозитория для выполнения домашних заданий (2-6) 4 | Форк создаст репозиторий на вашем http://github.com 5 | 6 | Добавьте ментора в коллаборацию 7 | 8 | Для каждой домашней работы создавайте свою ветку. 9 | 10 | - hw02 11 | - hw03 12 | - hw04 13 | - hw05 14 | - hw06 15 | 16 | Каждая новая ветка для дз должна делаться с master 17 | 18 | После того как вы закончили выполнять домашнее задание в своей ветке, необходимо сделать пулл-реквест (PR). Потом добавить ментора для ревью кода. Только после того как ментор заапрувит PR, вы можете выполнить мердж ветки с домашним заданием в мастер. 19 | 20 | Внимательно читайте комментарии ментора. Исправьте замечания и сделайте коммит в ветке с домашним заданием. Изменения подтянуться в PR автоматически после того как вы отправите коммит с исправлениями на github 21 | После исправления снова добавьте ментора на ревью кода. 22 | 23 | - При сдаче домашней работы есть ссылка на PR 24 | - JS-код чистый и понятный, для форматирования используется Prettier 25 | 26 | ### Команды: 27 | 28 | - `npm start` — старт сервера в режиме production 29 | - `npm run start:dev` — старт сервера в режиме разработки (development) 30 | - `npm run lint` — запустить выполнение проверки кода с eslint, необходимо выполнять перед каждым PR и исправлять все ошибки линтера 31 | - `npm lint:fix` — та же проверка линтера, но с автоматическими исправлениями простых ошибок 32 | -------------------------------------------------------------------------------- /lesson-10/pagination-mongoose/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {joiSchema, updateActiveJoiSchema} = require("../../models/product"); 4 | const {controllerWrapper, validation} = require("../../middlewares"); 5 | const {products: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | /* 10 | 1. Получить все товары. 11 | 2. Получить один товар по id. 12 | 3. Добавить товар. 13 | 4. Обновить товар по id. 14 | 5. Удалить товар по id. 15 | */ 16 | 17 | router.get("/", controllerWrapper(ctrl.getAll)); 18 | 19 | router.get("/:id", controllerWrapper(ctrl.getById)); 20 | 21 | router.post("/", validation(joiSchema), controllerWrapper(ctrl.add)); 22 | 23 | router.put("/:id", validation(joiSchema), controllerWrapper(ctrl.updateById)); 24 | 25 | router.patch("/:id/active", validation(updateActiveJoiSchema), controllerWrapper(ctrl.updateActive)); 26 | 27 | router.patch("/:id/code", validation(updateActiveJoiSchema), controllerWrapper(ctrl.updateCode)); 28 | 29 | router.delete("/:id", controllerWrapper(ctrl.removeById)); 30 | 31 | module.exports = router; -------------------------------------------------------------------------------- /lesson-10/slides/QA-work.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/slides/QA-work.jpg -------------------------------------------------------------------------------- /lesson-10/slides/Test-driven-development-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/slides/Test-driven-development-ru.png -------------------------------------------------------------------------------- /lesson-10/slides/developing-with-test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/slides/developing-with-test.jpg -------------------------------------------------------------------------------- /lesson-10/slides/piramida.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/slides/piramida.drawio.png -------------------------------------------------------------------------------- /lesson-10/slides/test-first-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/slides/test-first-schema.jpg -------------------------------------------------------------------------------- /lesson-10/slides/test-instruments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/slides/test-instruments.png -------------------------------------------------------------------------------- /lesson-10/slides/test-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/slides/test-schema.jpg -------------------------------------------------------------------------------- /lesson-10/test-function-example/app.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-10/test-function-example/app.js -------------------------------------------------------------------------------- /lesson-10/test-function-example/funcs/index.js: -------------------------------------------------------------------------------- 1 | const isLeapYear = require("./isLeapYear"); 2 | 3 | module.exports = { 4 | isLeapYear 5 | } -------------------------------------------------------------------------------- /lesson-10/test-function-example/funcs/isLeapYear.js: -------------------------------------------------------------------------------- 1 | const isLeapYear = (year)=> { 2 | if(year === undefined){ 3 | throw new Error('Год должен быть обязательно указан'); 4 | } 5 | if(typeof year !== "number"){ 6 | throw new Error('Год должен быть number'); 7 | } 8 | if(year < 42){ 9 | throw new Error('Год не может быть меньше 42'); 10 | } 11 | if(!Number.isInteger(year)){ 12 | throw new Error('Год должен быть целым числом'); 13 | } 14 | const date = new Date(year, 2, 0); 15 | const days = date.getDate(); 16 | 17 | return (days === 29); 18 | }; 19 | 20 | module.exports = isLeapYear -------------------------------------------------------------------------------- /lesson-10/test-function-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 19 | 20 | -------------------------------------------------------------------------------- /lesson-10/test-function-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-function-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "jest", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "jest": "^27.2.4", 16 | "nodemon": "^2.0.13" 17 | }, 18 | "dependencies": {} 19 | } 20 | -------------------------------------------------------------------------------- /lesson-11/auth-example/.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | SECRET_KEY= -------------------------------------------------------------------------------- /lesson-11/auth-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-11/auth-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | const mongoose = require("mongoose"); 4 | require("dotenv").config(); 5 | 6 | const authRouter = require("./routes/api/auth"); 7 | const ordersRouter = require("./routes/api/orders"); 8 | 9 | const app = express(); 10 | 11 | app.use(cors()); 12 | app.use(express.json()); 13 | 14 | app.use("/api/auth", authRouter); 15 | app.use("/api/orders", ordersRouter); 16 | 17 | app.use((req, res)=>{ 18 | res.status(404).json({ 19 | status: "error", 20 | code: 404, 21 | message: "Not Found" 22 | }) 23 | }); 24 | 25 | app.use((error, req, res, next)=>{ 26 | const {status = 500, message = "Server error"} = error; 27 | res.status(status).json({ 28 | status: "error", 29 | code: status, 30 | message 31 | }) 32 | }); 33 | 34 | const {DB_HOST, PORT = 3000} = process.env; 35 | // const {DB_USER, DB_USER_PASS, DB_NAME} = process.env; 36 | // const DB_HOST = `mongodb+srv://${DB_USER}:${DB_USER_PASS}@cluster0.fbkoo.mongodb.net/${DB_NAME}?retryWrites=true&w=majority` 37 | 38 | mongoose.connect(DB_HOST, { 39 | useNewUrlParser: true, 40 | useUnifiedTopology: true 41 | }).then(()=> app.listen(PORT)) 42 | .catch(error => { 43 | console.log(error.message); 44 | process.exit(1); 45 | }); -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/auth/index.js: -------------------------------------------------------------------------------- 1 | const register = require("./register"); 2 | const verify = require("./verify"); 3 | const login = require("./login"); 4 | const logout = require("./logout"); 5 | 6 | module.exports = { 7 | register, 8 | verify, 9 | login, 10 | logout 11 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/auth/login.js: -------------------------------------------------------------------------------- 1 | const {BadRequest} = require("http-errors"); 2 | const jwt = require("jsonwebtoken"); 3 | 4 | const {User} = require("../../models"); 5 | 6 | const {SECRET_KEY} = process.env; 7 | 8 | const login = async(req, res)=>{ 9 | const {email, password} = req.body; 10 | const user = await User.findOne({email}, "_id email password verify"); 11 | if(!user || !user.comparePassword(password)){ 12 | throw new BadRequest("Invalid email, password"); 13 | } 14 | 15 | if(!user.verify){ 16 | throw new BadRequest("Email not verify"); 17 | } 18 | 19 | const {_id} = user; 20 | const payload = { 21 | _id 22 | } 23 | const token = jwt.sign(payload, SECRET_KEY); 24 | 25 | await User.findByIdAndUpdate(_id, {token}); 26 | res.json({ 27 | status: "success", 28 | code: 200, 29 | data: { 30 | token 31 | } 32 | }) 33 | }; 34 | 35 | module.exports = login; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/auth/logout.js: -------------------------------------------------------------------------------- 1 | const {User} = require("../../models"); 2 | 3 | const logout = async(req, res)=>{ 4 | const {_id} = req.user; 5 | await User.findByIdAndUpdate(_id, {token: null}); 6 | res.json({ 7 | status: "success", 8 | code: 200, 9 | message: "Success logout" 10 | }); 11 | }; 12 | 13 | module.exports = logout; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/auth/register.js: -------------------------------------------------------------------------------- 1 | const {Conflict} = require("http-errors"); 2 | const {nanoid} = require("nanoid"); 3 | 4 | const {User} = require("../../models"); 5 | 6 | const {sendEmail}= require("../../helpers"); 7 | 8 | const register = async(req, res)=>{ 9 | const {email, password} = req.body; 10 | const user = await User.findOne({email}); 11 | if(user){ 12 | throw new Conflict("Already register"); 13 | } 14 | const verifyToken = nanoid(); 15 | const newUser = new User({ 16 | email, 17 | verifyToken 18 | }); 19 | newUser.setPassword(password); 20 | await newUser.save(); 21 | 22 | const data = { 23 | to: email, 24 | subject: "Подтверждения регистрации на сайте", 25 | html: ` 26 | Подтвердить почту 27 | ` 28 | } 29 | 30 | await sendEmail(data); 31 | res.status(201).json({ 32 | status: "success", 33 | code: 201, 34 | message: "Success register", 35 | data: { 36 | verifyToken 37 | } 38 | }); 39 | }; 40 | 41 | module.exports = register; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/auth/verify.js: -------------------------------------------------------------------------------- 1 | const {NotFound} = require("http-errors"); 2 | 3 | const {User} = require("../../models"); 4 | 5 | const verify = async(req, res)=> { 6 | const {verifyToken} = req.params; 7 | const user = await User.findOne({verifyToken}); 8 | if(!user){ 9 | throw new NotFound("Verify error"); 10 | } 11 | await User.findByIdAndUpdate(user._id, {verifyToken: null, verify: true}); 12 | res.json({ 13 | status: "success", 14 | code: 200, 15 | message: "Email verify success" 16 | }) 17 | }; 18 | 19 | module.exports = verify; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/index.js: -------------------------------------------------------------------------------- 1 | const auth = require("./auth"); 2 | const orders = require("./orders"); 3 | 4 | module.exports = { 5 | auth, 6 | orders 7 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/orders/add.js: -------------------------------------------------------------------------------- 1 | const {Order} = require("../../models"); 2 | 3 | const add = async(req, res)=> { 4 | const newOrder = {...req.body, owner: req.user._id}; 5 | const result = await Order.create(newOrder); 6 | res.status(201).json({ 7 | status: "success", 8 | code: 201, 9 | data: { 10 | result 11 | } 12 | }); 13 | }; 14 | 15 | module.exports = add; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/orders/getAll.js: -------------------------------------------------------------------------------- 1 | const {Order} = require("../../models"); 2 | 3 | const getAll = async(req, res)=>{ 4 | const result = await Order.find({}, "_id content owner"); 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | result 10 | } 11 | }) 12 | }; 13 | 14 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/orders/getAllByUser.js: -------------------------------------------------------------------------------- 1 | const {Order} = require("../../models"); 2 | 3 | const getAllByUser = async(req, res)=>{ 4 | const {_id} = req.user; 5 | const result = await Order.find({owner: _id}, "_id content owner"); 6 | res.json({ 7 | status: "success", 8 | code: 200, 9 | data: { 10 | result 11 | } 12 | }) 13 | }; 14 | 15 | module.exports = getAllByUser; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/orders/index.js: -------------------------------------------------------------------------------- 1 | const add = require("./add"); 2 | const getAllByUser = require("./getAllByUser"); 3 | const getAll = require("./getAll"); 4 | 5 | module.exports = { 6 | add, 7 | getAllByUser, 8 | getAll 9 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = require("./sendSuccessRes"); 2 | const sendEmail = require("./sendEmail"); 3 | 4 | module.exports = { 5 | sendSuccessRes, 6 | sendEmail 7 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/helpers/sendEmail.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | 3 | const {EMAIL_PASSWORD} = process.env; 4 | 5 | const nodemailerConfig = { 6 | host: "mail.adm.tools", 7 | port: 465, 8 | secure: true, 9 | auth: { 10 | user: "info@ntonyartist.com", 11 | pass: EMAIL_PASSWORD 12 | } 13 | }; 14 | 15 | const transporter = nodemailer.createTransport(nodemailerConfig); 16 | 17 | const sendEmail = async(data)=> { 18 | const email = { 19 | ...data, 20 | from: "info@ntonyartist.com", 21 | } 22 | await transporter.sendMail(email); 23 | }; 24 | 25 | module.exports = sendEmail; 26 | -------------------------------------------------------------------------------- /lesson-11/auth-example/helpers/sendSuccessRes.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = (res, data, status = 200)=> { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | } 8 | 9 | module.exports = sendSuccessRes -------------------------------------------------------------------------------- /lesson-11/auth-example/middlewares/authenticate.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | 3 | const {User} = require("../models"); 4 | 5 | const {SECRET_KEY} = process.env; 6 | 7 | const authenticate = async(req, res, next) => { 8 | const {authorization} = req.headers; 9 | if(!authorization){ 10 | res.status(401).json({ 11 | status: "error", 12 | code: 401, 13 | message: "Not authorized" 14 | }); 15 | return; 16 | } 17 | 18 | const [bearer, token] = authorization.split(" "); 19 | if(bearer !== "Bearer"){ 20 | res.status(401).json({ 21 | status: "error", 22 | code: 401, 23 | message: "Not authorized" 24 | }); 25 | return; 26 | } 27 | 28 | try { 29 | const {_id} = jwt.verify(token, SECRET_KEY); 30 | const user = await User.findById(_id); 31 | if(!user.token){ 32 | res.status(401).json({ 33 | status: "error", 34 | code: 401, 35 | message: "Not authorized" 36 | }); 37 | return; 38 | } 39 | req.user = user; 40 | next(); 41 | } 42 | catch (error) { 43 | res.status(401).json({ 44 | status: "error", 45 | code: 401, 46 | message: "Not authorized" 47 | }); 48 | return; 49 | } 50 | }; 51 | 52 | module.exports = authenticate; -------------------------------------------------------------------------------- /lesson-11/auth-example/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl) => { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch(error){ 7 | next(error); 8 | } 9 | } 10 | }; 11 | 12 | module.exports = controllerWrapper -------------------------------------------------------------------------------- /lesson-11/auth-example/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = require("./controllerWrapper"); 2 | const validation = require("./validation"); 3 | const authenticate = require("./authenticate"); 4 | 5 | module.exports = { 6 | controllerWrapper, 7 | validation, 8 | authenticate 9 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema) => { 2 | return async(req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | res.status(400).json({ 6 | status: "error", 7 | code: 400, 8 | message: error.message 9 | }); 10 | return; 11 | } 12 | next(); 13 | } 14 | }; 15 | 16 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-11/auth-example/models/index.js: -------------------------------------------------------------------------------- 1 | const {User} = require("./user"); 2 | const {Order} = require("./order"); 3 | 4 | module.exports = { 5 | User, 6 | Order 7 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/models/order.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | 4 | const orderSchema = Schema({ 5 | content: { 6 | type: String, 7 | required: true 8 | }, 9 | owner: { 10 | type: Schema.Types.ObjectId, 11 | ref: "user" 12 | } 13 | }, {versionKey: false, timestamps: true}); 14 | 15 | const joiSchema = Joi.object({ 16 | content: Joi.string().required() 17 | }); 18 | 19 | const Order = model("order", orderSchema); 20 | 21 | module.exports = { 22 | Order, 23 | joiSchema 24 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/models/user.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | const bcrypt = require("bcryptjs"); 4 | const jwt = require("jsonwebtoken"); 5 | 6 | const userSchema = Schema({ 7 | email: { 8 | type: String, 9 | required: true, 10 | unique: true 11 | }, 12 | password: { 13 | type: String, 14 | required: true, 15 | minlength: 6 16 | }, 17 | token: { 18 | type: String, 19 | default: null 20 | }, 21 | verify: { 22 | type: Boolean, 23 | default: false, 24 | }, 25 | verifyToken: { 26 | type: String, 27 | required: [true, 'Verify token is required'], 28 | }, 29 | }, {versionKey: false, timestamps: true}); 30 | 31 | userSchema.methods.setPassword = function(password){ 32 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)) 33 | } 34 | 35 | userSchema.methods.comparePassword = function(password){ 36 | return bcrypt.compareSync(password, this.password); 37 | } 38 | 39 | const {SECRET_KEY} = process.env; 40 | 41 | userSchema.methods.createToken = function(){ 42 | const payload = { 43 | _id: this._id 44 | }; 45 | return jwt.sign(payload, SECRET_KEY) 46 | } 47 | 48 | const joiSchema = Joi.object({ 49 | email: Joi.string().required(), 50 | password: Joi.string().min(6).required() 51 | }); 52 | 53 | const User = model("user", userSchema); 54 | 55 | module.exports = { 56 | User, 57 | joiSchema 58 | } 59 | -------------------------------------------------------------------------------- /lesson-11/auth-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auth-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "bcryptjs": "^2.4.3", 19 | "cors": "^2.8.5", 20 | "dotenv": "^10.0.0", 21 | "express": "^4.17.1", 22 | "http-errors": "^1.8.0", 23 | "joi": "^17.4.2", 24 | "jsonwebtoken": "^8.5.1", 25 | "mongoose": "^6.0.8", 26 | "nanoid": "^3.1.29", 27 | "nodemailer": "^6.7.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lesson-11/auth-example/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {joiSchema} = require("../../models/user"); 4 | const {controllerWrapper, validation, authenticate} = require("../../middlewares"); 5 | const {auth: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | // api/auth/register 10 | router.post("/register", validation(joiSchema), controllerWrapper(ctrl.register)); 11 | // router.post("/signup") 12 | 13 | router.get("/verify/:verifyToken", controllerWrapper(ctrl.verify)); 14 | 15 | router.post("/login", validation(joiSchema), controllerWrapper(ctrl.login)); 16 | // router.post("/signin") 17 | 18 | router.get("/logout", authenticate, controllerWrapper(ctrl.logout)); 19 | // router.get("/signuot") 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /lesson-11/auth-example/routes/api/orders.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {joiSchema} = require("../../models/order"); 4 | const {controllerWrapper, validation, authenticate} = require("../../middlewares"); 5 | const {orders: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", authenticate, controllerWrapper(ctrl.getAllByUser)); 10 | 11 | router.get("/all", controllerWrapper(ctrl.getAll)); 12 | 13 | router.post("/", authenticate, validation(joiSchema), controllerWrapper(ctrl.add)); 14 | 15 | module.exports = router; -------------------------------------------------------------------------------- /lesson-11/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-11/nodemailer-meta-ua/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-11/nodemailer-meta-ua/app.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | require("dotenv").config(); 3 | 4 | const {EMAIL_PASSWORD} = process.env; 5 | 6 | const nodemailerConfig = { 7 | host: "smtp.meta.ua", 8 | port: 465, 9 | secure: true, 10 | auth: { 11 | user: "bogdan.lyamzin.d@meta.ua", 12 | pass: EMAIL_PASSWORD 13 | } 14 | }; 15 | 16 | const transporter = nodemailer.createTransport(nodemailerConfig); 17 | 18 | const email = { 19 | to: "bogdan.lyamzin.d@gmail.com", 20 | from: "bogdan.lyamzin.d@meta.ua", 21 | subject: "Новая заявка с сайта", 22 | html: `

Email клиента: bogdan.lyamzin.d@gmail.com

23 |

Телефон клиента: 8-067 555-55-55

` 24 | }; 25 | 26 | transporter.sendMail(email) 27 | .then(()=> console.log("Email success send")) 28 | .catch(error => console.log(error.message)) -------------------------------------------------------------------------------- /lesson-11/nodemailer-meta-ua/helpers/sendEmail.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | 3 | const {EMAIL_PASSWORD} = process.env; 4 | 5 | const nodemailerConfig = { 6 | host: "smtp.meta.ua", 7 | port: 465, 8 | secure: true, 9 | auth: { 10 | user: "bogdan.lyamzin.d@meta.ua", 11 | pass: EMAIL_PASSWORD 12 | } 13 | }; 14 | 15 | const transporter = nodemailer.createTransport(nodemailerConfig); 16 | 17 | const sendEmail = async(data)=> { 18 | const email = { 19 | ...data, 20 | from: "bogdan.lyamzin.d@meta.ua", 21 | } 22 | await transporter.sendMail(email); 23 | }; 24 | 25 | module.exports = sendEmail; 26 | -------------------------------------------------------------------------------- /lesson-11/nodemailer-meta-ua/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodemailer", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "dotenv": "^10.0.0", 19 | "nodemailer": "^6.6.5" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lesson-11/nodemailer/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-11/nodemailer/app.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | require("dotenv").config(); 3 | 4 | const {EMAIL_PASSWORD} = process.env; 5 | 6 | const nodemailerConfig = { 7 | host: "mail.adm.tools", 8 | port: 465, 9 | secure: true, 10 | auth: { 11 | user: "info@ntonyartist.com", 12 | pass: EMAIL_PASSWORD 13 | } 14 | }; 15 | 16 | const transporter = nodemailer.createTransport(nodemailerConfig); 17 | 18 | const email = { 19 | to: "bogdan.lyamzin.d@gmail.com", 20 | from: "info@ntonyartist.com", 21 | subject: "Новая заявка с сайта", 22 | html: `

Email клиента: bogdan.lyamzin.d@gmail.com

23 |

Телефон клиента: 8-067 555-55-55

` 24 | }; 25 | 26 | transporter.sendMail(email) 27 | .then(()=> console.log("Email success send")) 28 | .catch(error => console.log(error.message)) -------------------------------------------------------------------------------- /lesson-11/nodemailer/helpers/sendEmail.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | 3 | const {EMAIL_PASSWORD} = process.env; 4 | 5 | const nodemailerConfig = { 6 | host: "mail.adm.tools", 7 | port: 465, 8 | secure: true, 9 | auth: { 10 | user: "info@ntonyartist.com", 11 | pass: EMAIL_PASSWORD 12 | } 13 | }; 14 | 15 | const transporter = nodemailer.createTransport(nodemailerConfig); 16 | 17 | const sendEmail = async(data)=> { 18 | const email = { 19 | ...data, 20 | from: "bogdan.lyamzin.d@meta.ua", 21 | } 22 | await transporter.sendMail(email); 23 | }; 24 | 25 | module.exports = sendEmail; 26 | -------------------------------------------------------------------------------- /lesson-11/nodemailer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodemailer", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "dotenv": "^10.0.0", 19 | "nodemailer": "^6.6.5" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lesson-11/sendgrid/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-11/sendgrid/app.js: -------------------------------------------------------------------------------- 1 | const sgMail = require("@sendgrid/mail"); 2 | require("dotenv").config(); 3 | 4 | const {SENDGRID_KEY} = process.env; 5 | 6 | sgMail.setApiKey(SENDGRID_KEY); 7 | 8 | const email = { 9 | to: "tokkagudru@vusra.com", 10 | from: "bogdan.lyamzin.d@gmail.com", 11 | subject: "Новая заявка с сайта", 12 | html: `

Email клиента: bogdan.lyamzin.d@gmail.com

13 |

Телефон клиента: 8-067 555-55-55

` 14 | }; 15 | 16 | sgMail.send(email) 17 | .then(()=> console.log("Email success send")) 18 | .catch(error => console.log(error.message)) -------------------------------------------------------------------------------- /lesson-11/sendgrid/helpers/sendEmail.js: -------------------------------------------------------------------------------- 1 | const sgMail = require("@sendgrid/mail"); 2 | require("dotenv").config(); 3 | 4 | const {SENDGRID_KEY} = process.env; 5 | 6 | sgMail.setApiKey(SENDGRID_KEY); 7 | 8 | const sendEmail = async(data)=> { 9 | const email = {...data, from: "bogdan.lyamzin.d@gmail.com"} 10 | await sgMail.send(email); 11 | }; 12 | 13 | module.exports = sendEmail; 14 | 15 | -------------------------------------------------------------------------------- /lesson-11/sendgrid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sendgrid", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "@sendgrid/mail": "^7.4.7", 19 | "dotenv": "^10.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lesson-11/slides/mailing-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-11/slides/mailing-schema.jpg -------------------------------------------------------------------------------- /lesson-11/slides/nodemailer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-11/slides/nodemailer.jpg -------------------------------------------------------------------------------- /lesson-11/slides/sendgrid-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-11/slides/sendgrid-schema.jpg -------------------------------------------------------------------------------- /lesson-12/README.md: -------------------------------------------------------------------------------- 1 | [Где применяются веб-сокеты](./slides/websocket-projects.jpg) 2 | 3 | [Разница между веб-сокетами и HTTP](./slides/different-between-websockets-and-http.jpg) 4 | 5 | [Основные нюансы вет-сокет протокола](./slides/websocket-main-features.jpg) 6 | 7 | [Схема взаимодействия клиент-сервер у веб-сокетов](./slides/web-socket-client-server-schema.jpg) 8 | 9 | [Принцип работы с каждым отдельным клиентом у веб-сокетов](./slides/web-socket-personal-client-object.jpg) -------------------------------------------------------------------------------- /lesson-12/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-12/mongodb-project/.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= -------------------------------------------------------------------------------- /lesson-12/mongodb-project/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | yarn.log 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-12/mongodb-project/app.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const express = require("express"); 3 | const cors = require("cors"); 4 | require("dotenv").config(); 5 | 6 | const productsRouter = require("./routes/api/products"); 7 | 8 | const app = express(); 9 | 10 | app.use(cors()); 11 | app.use(express.json()); 12 | 13 | app.use("/api/products", productsRouter); 14 | 15 | app.use((_, res)=>{ 16 | res.status(404).json({ 17 | status: "error", 18 | code: 404, 19 | message: "Not found" 20 | }); 21 | }); 22 | 23 | app.use((error, _, res, __)=> { 24 | const {status = 500, message = "Server error"} = error; 25 | res.status(status).json({ 26 | status: "error", 27 | code: status, 28 | message 29 | }) 30 | }); 31 | 32 | const {DB_HOST, PORT = 3000} = process.env; 33 | 34 | mongoose.connect(DB_HOST, { 35 | useNewUrlParser: true, 36 | useUnifiedTopology: true 37 | }).then(()=>{ 38 | app.listen(PORT); 39 | }) 40 | .catch(error => { 41 | console.log(error.message); 42 | process.exit(1); 43 | }); -------------------------------------------------------------------------------- /lesson-12/mongodb-project/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | 3 | module.exports = { 4 | products 5 | } -------------------------------------------------------------------------------- /lesson-12/mongodb-project/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessReq = require("./sendSuccessReq"); 2 | 3 | module.exports = { 4 | sendSuccessReq 5 | } -------------------------------------------------------------------------------- /lesson-12/mongodb-project/helpers/sendSuccessReq.js: -------------------------------------------------------------------------------- 1 | const sendSuccessReq = (res, data, status = 200) => { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | }; 8 | 9 | module.exports = sendSuccessReq; -------------------------------------------------------------------------------- /lesson-12/mongodb-project/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch (error) { 7 | next(error); 8 | } 9 | } 10 | } 11 | 12 | module.exports = controllerWrapper; -------------------------------------------------------------------------------- /lesson-12/mongodb-project/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const controllerWrapper = require("./controllerWrapper"); 3 | 4 | module.exports = { 5 | validation, 6 | controllerWrapper 7 | } -------------------------------------------------------------------------------- /lesson-12/mongodb-project/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next) => { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | return res.status(400).json({ 6 | status: "error", 7 | code: 400, 8 | message: error.message 9 | }); 10 | } 11 | next(); 12 | } 13 | }; 14 | 15 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-12/mongodb-project/models/category.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-12/mongodb-project/models/category.js -------------------------------------------------------------------------------- /lesson-12/mongodb-project/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | 3 | module.exports = { 4 | Product 5 | } -------------------------------------------------------------------------------- /lesson-12/mongodb-project/models/product.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | const {Schema, model} = require("mongoose"); 3 | 4 | const codeRegexp = /^[0-9]{5}$/; 5 | 6 | const productSchema = Schema({ 7 | name: { 8 | type: String, 9 | required: [true, "Имя товара обязательно"] 10 | }, 11 | description: { 12 | type: String, 13 | required: [true, "Описание товара обязательно"], 14 | minlength: 2 15 | }, 16 | price: { 17 | type: Number, 18 | required: [true, "Цена товара обязательна"], 19 | min: 0.01 20 | }, 21 | isActive: { 22 | type: Boolean, 23 | default: true 24 | }, 25 | // status: stock, priceLow, basic 26 | status: { 27 | type: String, 28 | enum: ["stock", "priceLow", "basic"], 29 | default: "basic" 30 | }, 31 | code: { 32 | type: String, 33 | match: [codeRegexp, "Код - это строка из 5 чисел"], 34 | required: [true, "Код должен быть обязательно указан"], 35 | unique: true 36 | } 37 | }, {versionKey: false, timestamps: true}); 38 | 39 | const joiSchema = Joi.object({ 40 | name: Joi.string().required(), 41 | description: Joi.string().required(), 42 | price: Joi.number().min(0.01).required(), 43 | isActive: Joi.boolean(), 44 | status: Joi.string(), 45 | code: Joi.string().pattern(codeRegexp) 46 | }); 47 | 48 | const Product = model("product", productSchema); 49 | 50 | module.exports = {Product, joiSchema}; -------------------------------------------------------------------------------- /lesson-12/mongodb-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-project-2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "dotenv": "^10.0.0", 20 | "express": "^4.17.1", 21 | "http-errors": "^1.8.0", 22 | "joi": "^17.4.2", 23 | "mongoose": "^6.0.6" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lesson-12/mongodb-project/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {validation, controllerWrapper} = require("../../middlewares"); 4 | const {joiSchema} = require("../../models/product"); 5 | const {products: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", controllerWrapper(ctrl.getAll)); 10 | 11 | router.get("/:id", controllerWrapper(ctrl.getById)); 12 | 13 | router.post("/", validation(joiSchema), controllerWrapper(ctrl.add)); 14 | 15 | router.put("/:id", validation(joiSchema), controllerWrapper(ctrl.updateById)); 16 | 17 | router.patch("/:id", controllerWrapper(ctrl.updateStatus)); 18 | 19 | router.delete("/:id", controllerWrapper(ctrl.removeById)); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /lesson-12/slides/different-between-websockets-and-http.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-12/slides/different-between-websockets-and-http.jpg -------------------------------------------------------------------------------- /lesson-12/slides/web-socket-client-server-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-12/slides/web-socket-client-server-schema.jpg -------------------------------------------------------------------------------- /lesson-12/slides/web-socket-personal-client-object.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-12/slides/web-socket-personal-client-object.jpg -------------------------------------------------------------------------------- /lesson-12/slides/websocket-main-features.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-12/slides/websocket-main-features.jpg -------------------------------------------------------------------------------- /lesson-12/slides/websocket-projects.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-12/slides/websocket-projects.jpg -------------------------------------------------------------------------------- /lesson-12/web-socket-chat-example/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-12/web-socket-chat-example/app.js: -------------------------------------------------------------------------------- 1 | const ws = new require("ws"); 2 | 3 | const wsServer = new ws.Server({port: 5000}); 4 | 5 | const users = []; 6 | 7 | wsServer.on("connection", (newUser)=>{ 8 | users.push(newUser); 9 | 10 | newUser.on("message", (message)=> { 11 | users.forEach(user => { 12 | if(user !== newUser){ 13 | user.send(message); 14 | } 15 | }); 16 | }) 17 | }); -------------------------------------------------------------------------------- /lesson-12/web-socket-chat-example/frontend/style.css: -------------------------------------------------------------------------------- 1 | .chat { 2 | width: 242px; 3 | margin-bottom: 15px; 4 | border: 1px solid; 5 | } 6 | 7 | .chat p { 8 | margin: 10px 5px 25px; 9 | } 10 | 11 | .enter-chat-message { 12 | font-size: 18px; 13 | font-weight: bold; 14 | font-family: Arial, Helvetica, sans-serif; 15 | padding: 5px; 16 | border-radius: 5px; 17 | display: inline-block; 18 | } 19 | 20 | .you-chat-message { 21 | font-size: 16px; 22 | font-family: Arial, Helvetica, sans-serif; 23 | background-color: lightgray; 24 | padding: 5px; 25 | border-radius: 5px; 26 | display: inline-block; 27 | } 28 | 29 | .user-chat-message { 30 | font-size: 16px; 31 | font-family: Arial, Helvetica, sans-serif; 32 | text-align: right; 33 | background-color: lightskyblue; 34 | padding: 5px; 35 | border-radius: 5px; 36 | display: inline-block; 37 | } -------------------------------------------------------------------------------- /lesson-12/web-socket-chat-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-socket-chat-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.9" 16 | }, 17 | "dependencies": { 18 | "ws": "^7.5.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-12/websocket-basic-example/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-12/websocket-basic-example/app.js: -------------------------------------------------------------------------------- 1 | const ws = new require("ws"); 2 | 3 | const wsServer = new ws.Server({port: 5000}); 4 | 5 | const clients = []; 6 | 7 | wsServer.on("connection", (newClient)=>{ 8 | clients.push(newClient); 9 | newClient.send("Добро пожаловать в компанию!"); 10 | 11 | newClient.on("message", (message)=> { 12 | console.log(message); 13 | }); 14 | 15 | clients.forEach(client => { 16 | if(client !== newClient){ 17 | client.send("У нас новый член команды") 18 | } 19 | }); 20 | // console.log("Новое подключение с фронтенда") 21 | }); -------------------------------------------------------------------------------- /lesson-12/websocket-basic-example/frontend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 23 | 24 | -------------------------------------------------------------------------------- /lesson-12/websocket-basic-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "websocket-basic-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.8" 16 | }, 17 | "dependencies": { 18 | "ws": "^7.5.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-13/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-13/mongodb-project/.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= -------------------------------------------------------------------------------- /lesson-13/mongodb-project/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | yarn.log 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-13/mongodb-project/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | RUN npm install 8 | 9 | EXPOSE 3000 10 | 11 | CMD ["node", "app"] 12 | 13 | -------------------------------------------------------------------------------- /lesson-13/mongodb-project/app.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const express = require("express"); 3 | const cors = require("cors"); 4 | require("dotenv").config(); 5 | 6 | const productsRouter = require("./routes/api/products"); 7 | 8 | const app = express(); 9 | 10 | app.use(cors()); 11 | app.use(express.json()); 12 | 13 | app.use("/api/products", productsRouter); 14 | 15 | app.use((_, res)=>{ 16 | res.status(404).json({ 17 | status: "error", 18 | code: 404, 19 | message: "Not found" 20 | }); 21 | }); 22 | 23 | app.use((error, _, res, __)=> { 24 | const {status = 500, message = "Server error"} = error; 25 | res.status(status).json({ 26 | status: "error", 27 | code: status, 28 | message 29 | }) 30 | }); 31 | 32 | const {DB_HOST, PORT = 3000} = process.env; 33 | 34 | mongoose.connect(DB_HOST, { 35 | useNewUrlParser: true, 36 | useUnifiedTopology: true 37 | }).then(()=>{ 38 | app.listen(PORT); 39 | }) 40 | .catch(error => { 41 | console.log(error.message); 42 | process.exit(1); 43 | }); -------------------------------------------------------------------------------- /lesson-13/mongodb-project/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | 3 | module.exports = { 4 | products 5 | } -------------------------------------------------------------------------------- /lesson-13/mongodb-project/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessReq = require("./sendSuccessReq"); 2 | 3 | module.exports = { 4 | sendSuccessReq 5 | } -------------------------------------------------------------------------------- /lesson-13/mongodb-project/helpers/sendSuccessReq.js: -------------------------------------------------------------------------------- 1 | const sendSuccessReq = (res, data, status = 200) => { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | }; 8 | 9 | module.exports = sendSuccessReq; -------------------------------------------------------------------------------- /lesson-13/mongodb-project/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch (error) { 7 | next(error); 8 | } 9 | } 10 | } 11 | 12 | module.exports = controllerWrapper; -------------------------------------------------------------------------------- /lesson-13/mongodb-project/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const controllerWrapper = require("./controllerWrapper"); 3 | 4 | module.exports = { 5 | validation, 6 | controllerWrapper 7 | } -------------------------------------------------------------------------------- /lesson-13/mongodb-project/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next) => { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | return res.status(400).json({ 6 | status: "error", 7 | code: 400, 8 | message: error.message 9 | }); 10 | } 11 | next(); 12 | } 13 | }; 14 | 15 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-13/mongodb-project/models/category.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/mongodb-project/models/category.js -------------------------------------------------------------------------------- /lesson-13/mongodb-project/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | 3 | module.exports = { 4 | Product 5 | } -------------------------------------------------------------------------------- /lesson-13/mongodb-project/models/product.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | const {Schema, model} = require("mongoose"); 3 | 4 | const codeRegexp = /^[0-9]{5}$/; 5 | 6 | const productSchema = Schema({ 7 | name: { 8 | type: String, 9 | required: [true, "Имя товара обязательно"] 10 | }, 11 | description: { 12 | type: String, 13 | required: [true, "Описание товара обязательно"], 14 | minlength: 2 15 | }, 16 | price: { 17 | type: Number, 18 | required: [true, "Цена товара обязательна"], 19 | min: 0.01 20 | }, 21 | isActive: { 22 | type: Boolean, 23 | default: true 24 | }, 25 | // status: stock, priceLow, basic 26 | status: { 27 | type: String, 28 | enum: ["stock", "priceLow", "basic"], 29 | default: "basic" 30 | }, 31 | code: { 32 | type: String, 33 | match: [codeRegexp, "Код - это строка из 5 чисел"], 34 | required: [true, "Код должен быть обязательно указан"], 35 | unique: true 36 | } 37 | }, {versionKey: false, timestamps: true}); 38 | 39 | const joiSchema = Joi.object({ 40 | name: Joi.string().required(), 41 | description: Joi.string().required(), 42 | price: Joi.number().min(0.01).required(), 43 | isActive: Joi.boolean(), 44 | status: Joi.string(), 45 | code: Joi.string().pattern(codeRegexp) 46 | }); 47 | 48 | const Product = model("product", productSchema); 49 | 50 | module.exports = {Product, joiSchema}; -------------------------------------------------------------------------------- /lesson-13/mongodb-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-project-2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "dotenv": "^10.0.0", 20 | "express": "^4.17.1", 21 | "http-errors": "^1.8.0", 22 | "joi": "^17.4.2", 23 | "mongoose": "^6.0.6" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lesson-13/mongodb-project/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {validation, controllerWrapper} = require("../../middlewares"); 4 | const {joiSchema} = require("../../models/product"); 5 | const {products: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", controllerWrapper(ctrl.getAll)); 10 | 11 | router.get("/:id", controllerWrapper(ctrl.getById)); 12 | 13 | router.post("/", validation(joiSchema), controllerWrapper(ctrl.add)); 14 | 15 | router.put("/:id", validation(joiSchema), controllerWrapper(ctrl.updateById)); 16 | 17 | router.patch("/:id", controllerWrapper(ctrl.updateStatus)); 18 | 19 | router.delete("/:id", controllerWrapper(ctrl.removeById)); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /lesson-13/php-project/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | CMD ["php", "index.php"] -------------------------------------------------------------------------------- /lesson-13/php-project/index.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-13/slides/05efe6379b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/05efe6379b.jpg -------------------------------------------------------------------------------- /lesson-13/slides/09bf934cc1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/09bf934cc1.jpg -------------------------------------------------------------------------------- /lesson-13/slides/0aac227e26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/0aac227e26.jpg -------------------------------------------------------------------------------- /lesson-13/slides/1e8868fd69.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/1e8868fd69.jpg -------------------------------------------------------------------------------- /lesson-13/slides/206360c857.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/206360c857.jpg -------------------------------------------------------------------------------- /lesson-13/slides/35e71d29de.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/35e71d29de.jpg -------------------------------------------------------------------------------- /lesson-13/slides/505114e755.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/505114e755.jpg -------------------------------------------------------------------------------- /lesson-13/slides/6423d760db.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/6423d760db.jpg -------------------------------------------------------------------------------- /lesson-13/slides/7155b6b76d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/7155b6b76d.jpg -------------------------------------------------------------------------------- /lesson-13/slides/76a678f8e7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/76a678f8e7.jpg -------------------------------------------------------------------------------- /lesson-13/slides/83fc82807e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/83fc82807e.jpg -------------------------------------------------------------------------------- /lesson-13/slides/9b35bf3889.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/9b35bf3889.jpg -------------------------------------------------------------------------------- /lesson-13/slides/a7cc498c22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/a7cc498c22.jpg -------------------------------------------------------------------------------- /lesson-13/slides/b78636dee9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/b78636dee9.jpg -------------------------------------------------------------------------------- /lesson-13/slides/ca8261d313.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/ca8261d313.jpg -------------------------------------------------------------------------------- /lesson-13/slides/daf8a4de74.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-13/slides/daf8a4de74.jpg -------------------------------------------------------------------------------- /lesson-2/README.md: -------------------------------------------------------------------------------- 1 | [Где используется работа с файлами в Node.js](./slides/work-with-files-examples.png) 2 | -------------------------------------------------------------------------------- /lesson-2/file-reader/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-2/file-reader/files/read.txt: -------------------------------------------------------------------------------- 1 | Мишка очень любит мед. -------------------------------------------------------------------------------- /lesson-2/file-reader/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | fs.readFile("files/read.txt", "utf-8", (error, data)=>{ 4 | if(error){ 5 | throw error; 6 | } 7 | console.log(data); 8 | // const text = data.toString(); 9 | // console.log(text); 10 | // console.log(error); 11 | // console.log(data); 12 | }); -------------------------------------------------------------------------------- /lesson-2/file-reader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "file-reader", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index", 9 | "start:dev": "nodemon index" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lesson-2/file-reader/promise-index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | // const fs = require("fs").promises; 3 | 4 | // (async()=>{ 5 | // try { 6 | // const data = await fs.readFile("files/read.txt", "utf-8"); 7 | // console.log(data); 8 | // } 9 | // catch(error){ 10 | // console.log(error); 11 | // } 12 | // })(); 13 | 14 | const readFile = async(filePath) => { 15 | try { 16 | const data = await fs.readFile(filePath, "utf-8"); 17 | return data; 18 | } 19 | catch(error){ 20 | throw error; 21 | } 22 | }; 23 | 24 | readFile("files/read.txt") 25 | .then(data => console.log(data)) 26 | .catch(error => console.log(error)); 27 | 28 | // fs.readFile("files/read.txt", "utf-8") 29 | // .then(data => console.log(data)) 30 | // .catch(error => console.log(error)); -------------------------------------------------------------------------------- /lesson-2/slides/work-with-files-examples.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-2/slides/work-with-files-examples.jpg -------------------------------------------------------------------------------- /lesson-2/work-with-files/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-2/work-with-files/app.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const fileOperation = async(filePath, type = "read", data = "") => { 4 | switch(type){ 5 | case "read": 6 | return await fs.readFile(filePath, "utf-8"); 7 | case "add": 8 | await fs.appendFile(filePath, data); 9 | return await fs.readFile(filePath, "utf-8"); 10 | case "rewrite": 11 | await fs.writeFile(filePath, data); 12 | return await fs.readFile(filePath, "utf-8"); 13 | case "remove": 14 | return await fs.unlink(filePath); 15 | default: 16 | return "Unknown command"; 17 | } 18 | }; 19 | 20 | // fileOperation("file.txt") 21 | // .then(data => console.log(data)) 22 | // .catch(error => console.log(error)); 23 | 24 | // fileOperation("file.txt", "add", "\nНичего я не говорил") 25 | // .then(data => console.log(data)) 26 | // .catch(error => console.log(error)); 27 | 28 | fileOperation("file.txt", "rewrite", "Ничего я не говорил") 29 | .then(data => console.log(data)) 30 | .catch(error => console.log(error)); 31 | 32 | // fileOperation("file.txt", "remove") 33 | // .then(_ => console.log("Success remove")) 34 | // .catch(error => console.log(error)); 35 | 36 | -------------------------------------------------------------------------------- /lesson-2/work-with-files/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "work-with-files", 3 | "version": "1.0.0", 4 | "main": "app.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "start": "node app", 8 | "start:dev": "nodemon app" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "nodemon": "^2.0.12" 15 | }, 16 | "description": "" 17 | } 18 | -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "work-with-json-files", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "uuid": "^8.3.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/add.js: -------------------------------------------------------------------------------- 1 | const {v4} = require("uuid"); 2 | 3 | const updateProducts = require("./updateProducts"); 4 | const getAll = require("./getAll"); 5 | 6 | 7 | 8 | module.exports = add; 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/getAll.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-2/work-with-json-files-example-2/products/getAll.js -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/getById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | 3 | 4 | 5 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/index.js: -------------------------------------------------------------------------------- 1 | const {v4} = require("uuid"); 2 | const fs = require("fs/promises"); 3 | const path = require("path"); 4 | 5 | const products = require("./products.json"); 6 | 7 | const filePath = path.join(__dirname, "products.json"); 8 | 9 | const updateProducts = async(newProducts) => { 10 | await fs.writeFile(filePath, JSON.stringify(newProducts)); 11 | }; 12 | 13 | const getAll = async() => products; 14 | 15 | const getById = async(id) => { 16 | const product = products.find(item => item.id === id); 17 | if(!product) { 18 | return null; 19 | } 20 | return product; 21 | } 22 | 23 | const add = async(data) => { 24 | const newProduct = {...data, id: v4()}; 25 | products.push(newProduct); 26 | await updateProducts(products); 27 | return newProduct; 28 | } 29 | 30 | const updateById = async(id, data) => { 31 | const idx = products.findIndex(item => item.id === id); 32 | if(idx === -1){ 33 | return null; 34 | } 35 | const updateProduct = {...products[idx], ...data}; 36 | products[idx] = updateProduct; 37 | await updateProducts(products); 38 | return updateProduct; 39 | }; 40 | 41 | 42 | module.exports = { 43 | getAll, 44 | getById, 45 | add, 46 | updateById, 47 | removeById 48 | } 49 | 50 | -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "48bd1cd8-72ca-42cc-8457-156bb8c30873", 4 | "name": "cheese", 5 | "price": 2.5, 6 | "location": "Refrigerated foods" 7 | }, 8 | { 9 | "id": "61c0169c-e693-4a20-af3e-2e55fdc34f79", 10 | "name": "Crisps", 11 | "price": 4, 12 | "location": "the Snack isle" 13 | }, 14 | { 15 | "id": "2c9c3d67-07b3-4ee1-a59f-67d54427d3c3", 16 | "name": "Pizza", 17 | "price": 4, 18 | "location": "Refrigerated foods" 19 | }, 20 | { 21 | "id": "2386a63f-140a-494c-b4e5-b23a219bbac0", 22 | "name": "Chocolate", 23 | "price": 1.5, 24 | "location": "the Snack isle" 25 | }, 26 | { 27 | "id": "8263b539-c546-4a64-866d-97d58e42c585", 28 | "name": "Self-raising flour", 29 | "price": 1.5, 30 | "location": "Home baking" 31 | }, 32 | { 33 | "id": "767580d5-f509-4f45-98f9-28e74ec4af66", 34 | "name": "Ground almonds", 35 | "price": 4, 36 | "location": "Home baking" 37 | } 38 | ] -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/removeById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 3 | 4 | const removeById = async(id) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1) { 8 | return null; 9 | } 10 | // const newProducts = products.filter(item => item.id !== id); 11 | products.splice(idx, 1); 12 | await updateProducts(products); 13 | // await updateProducts(newProducts); 14 | return "Success remove" 15 | } 16 | 17 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/updateById.js: -------------------------------------------------------------------------------- 1 | const updateProducts = require("./updateProducts"); 2 | const getAll = require("./getAll"); 3 | 4 | const updateById = async(id, data) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1){ 8 | return null; 9 | } 10 | const updateProduct = {...products[idx], ...data}; 11 | products[idx] = updateProduct; 12 | await updateProducts(products); 13 | return updateProduct; 14 | }; 15 | 16 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files-example-2/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | 5 | 6 | module.exports = updateProducts; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "work-with-json-files", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "uuid": "^8.3.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/add.js: -------------------------------------------------------------------------------- 1 | const {v4} = require("uuid"); 2 | 3 | const updateProducts = require("./updateProducts"); 4 | const getAll = require("./getAll"); 5 | 6 | const add = async(data) => { 7 | const products = await getAll(); 8 | const newProduct = {...data, id: v4()}; 9 | products.push(newProduct); 10 | // const newProducts = [...products, newProduct]; 11 | await updateProducts(products); 12 | // await updateProducts(newProducts); 13 | return newProduct; 14 | } 15 | 16 | module.exports = add; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/getAll.js: -------------------------------------------------------------------------------- 1 | const products = require("./products.json"); 2 | /* 3 | const data = fs.readFileSync("./products.json"); 4 | const products = JSON.parse(data); 5 | */ 6 | const getAll = async() => products; 7 | 8 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/getById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | 3 | const getById = async(id) => { 4 | const products = await getAll(); 5 | const product = products.find(item => item.id === id); 6 | if(!product) { 7 | return null; 8 | } 9 | return product; 10 | } 11 | 12 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/index.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const getById = require("./getById"); 3 | const add = require("./add"); 4 | const updateById = require("./updateById"); 5 | const removeById = require("./removeById"); 6 | 7 | module.exports = { 8 | getAll, 9 | getById, 10 | add, 11 | updateById, 12 | removeById 13 | } 14 | 15 | -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "48bd1cd8-72ca-42cc-8457-156bb8c30873", 4 | "name": "cheese", 5 | "price": 2.5, 6 | "location": "Refrigerated foods" 7 | }, 8 | { 9 | "id": "61c0169c-e693-4a20-af3e-2e55fdc34f79", 10 | "name": "Crisps", 11 | "price": 4, 12 | "location": "the Snack isle" 13 | }, 14 | { 15 | "id": "2c9c3d67-07b3-4ee1-a59f-67d54427d3c3", 16 | "name": "Pizza", 17 | "price": 4, 18 | "location": "Refrigerated foods" 19 | }, 20 | { 21 | "id": "2386a63f-140a-494c-b4e5-b23a219bbac0", 22 | "name": "Chocolate", 23 | "price": 1.5, 24 | "location": "the Snack isle" 25 | }, 26 | { 27 | "id": "8263b539-c546-4a64-866d-97d58e42c585", 28 | "name": "Self-raising flour", 29 | "price": 1.5, 30 | "location": "Home baking" 31 | }, 32 | { 33 | "id": "767580d5-f509-4f45-98f9-28e74ec4af66", 34 | "name": "Ground almonds", 35 | "price": 4, 36 | "location": "Home baking" 37 | } 38 | ] -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/removeById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 3 | 4 | const removeById = async(id) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1) { 8 | return null; 9 | } 10 | // const newProducts = products.filter(item => item.id !== id); 11 | products.splice(idx, 1); 12 | await updateProducts(products); 13 | // await updateProducts(newProducts); 14 | return "Success remove" 15 | } 16 | 17 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/updateById.js: -------------------------------------------------------------------------------- 1 | const updateProducts = require("./updateProducts"); 2 | const getAll = require("./getAll"); 3 | 4 | const updateById = async(id, data) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1){ 8 | return null; 9 | } 10 | const updateProduct = {...products[idx], ...data}; 11 | products[idx] = updateProduct; 12 | await updateProducts(products); 13 | return updateProduct; 14 | }; 15 | 16 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | const filePath = path.join(__dirname, "products.json"); 5 | 6 | const updateProducts = async(newProducts) => { 7 | await fs.writeFile(filePath, JSON.stringify(newProducts)); 8 | }; 9 | 10 | module.exports = updateProducts; -------------------------------------------------------------------------------- /lesson-3/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | .env 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-3/README.md: -------------------------------------------------------------------------------- 1 | [Схема взаимодействия клиента и сервера](./slides/Client-Server-schema.jpg) 2 | 3 | [Как работают middleware в express](./slides/middleware-work-schema.jpg) 4 | 5 | [Как работают middleware в express](./slides/middleware-work-schema.jpg) 6 | 7 | [Более подробно - как работают middleware в express](./slides/middleware-work-schema-details.jpg) 8 | 9 | [Middleware в express как оглавление записной книжки](./slides/middleware-work-schema-details-2.jpg) 10 | 11 | [Middleware в express как набор обязательных действий на ресепшен](./slides/middleware-work-schema-details-3.jpg) 12 | 13 | [Что такое CORS - кросс-доменные запросы](./slides/what-is-it-cors.jpg) 14 | 15 | [Проблемы с CORS при разработки одновремено фронтенда и бекенда](./slides/fullstack-developer-cors-problem.jpg) 16 | 17 | [Проблемы с CORS когда бекенд задеплоен на удаленный сервер](./slides/fullstack-developer-cors-problem-2.jpg) -------------------------------------------------------------------------------- /lesson-3/express-example-1/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | .env 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-3/express-example-1/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const app = express(); 4 | 5 | app.get("/", (request, response)=>{ 6 | response.send("

Главная страница

"); 7 | }); 8 | 9 | app.get("/contacts", (request, response)=>{ 10 | response.send("

Наши контакты

"); 11 | }); 12 | 13 | app.get("/about-us", (request, response)=> { 14 | console.log(request.url); 15 | console.log(request.method); 16 | console.log(request.headers); 17 | response.send("

О нас

"); 18 | }); 19 | 20 | app.listen(3000); 21 | 22 | -------------------------------------------------------------------------------- /lesson-3/express-example-1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example-1", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "express": "^4.17.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-3/express-example-2/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | .env 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-3/express-example-2/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const products = require("./products"); 4 | 5 | const app = express(); 6 | 7 | // app.set("space", 8); 8 | // app.set("json replacer", " "); 9 | 10 | app.get("/products", (req, res) => { 11 | res.json({ 12 | status: "success", 13 | data: { 14 | result: products 15 | } 16 | }); 17 | // res.json(null); 18 | // res.send(null); 19 | }); 20 | 21 | app.post("/products", (req, res)=> { 22 | res.send({ 23 | message: "товар успешно добавлен" 24 | }); 25 | }); 26 | 27 | app.listen(3000); -------------------------------------------------------------------------------- /lesson-3/express-example-2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example-2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "express": "^4.17.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-3/express-example-2/products.js: -------------------------------------------------------------------------------- 1 | const products = [ 2 | { 3 | _id: "34ggffg", 4 | name: "iPhone X", 5 | price: 34000 6 | }, 7 | { 8 | _id: "dffgsdgdg", 9 | name: "GeForce RTX 3090", 10 | price: 90000 11 | } 12 | ]; 13 | 14 | module.exports = products; -------------------------------------------------------------------------------- /lesson-3/express-example-3/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | .env 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-3/express-example-3/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const fs = require("fs/promises"); 3 | const moment = require("moment"); 4 | const cors = require("cors"); 5 | 6 | const products = require("./products"); 7 | 8 | const app = express(); 9 | 10 | app.use(cors()); 11 | 12 | // 15.09.2021_21:03:54 GET /products 13 | // 15.09.2021_21:04:05 POST /products 14 | 15 | // app.use(async (req, res, next)=> { 16 | // const {url, method} = req; 17 | // const now = moment().format("DD.MM.YYYY_hh:mm:ss"); 18 | // const data = `\n${now} ${method} ${url}`; 19 | // await fs.appendFile("server.log", data); 20 | // next(); 21 | // }); 22 | 23 | // app.use((req, res, next)=> { 24 | // console.log("First middleware"); 25 | // next(); 26 | // }); 27 | 28 | // app.use((req, res)=> { 29 | // console.log("Second middleware"); 30 | // next(); 31 | // }); 32 | 33 | app.get("/products", (req, res)=> { 34 | res.json(products); 35 | }); 36 | 37 | app.post("/products", (req, res)=> { 38 | res.json({ 39 | message: "Товар успешно добавлен" 40 | }) 41 | }); 42 | 43 | // app.use((req, res, next)=> { 44 | // console.log("Last middleware"); 45 | // }); 46 | 47 | 48 | 49 | app.listen(3000); -------------------------------------------------------------------------------- /lesson-3/express-example-3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /lesson-3/express-example-3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example-3", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "express": "^4.17.1", 20 | "moment": "^2.29.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lesson-3/express-example-3/products.js: -------------------------------------------------------------------------------- 1 | const products = [ 2 | { 3 | _id: "34ggffg", 4 | name: "iPhone X", 5 | price: 34000 6 | }, 7 | { 8 | _id: "dffgsdgdg", 9 | name: "GeForce RTX 3090", 10 | price: 90000 11 | } 12 | ]; 13 | 14 | module.exports = products; -------------------------------------------------------------------------------- /lesson-3/express-example-3/server.log: -------------------------------------------------------------------------------- 1 | 15.09.2021_09:16:34 GET /products 2 | 15.09.2021_09:16:52 POST /products -------------------------------------------------------------------------------- /lesson-3/http-server-example/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | .env 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-3/http-server-example/app.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | // request - объект, описывающий весь запрос 3 | // response - объект, описывающий весь ответ 4 | 5 | const server = http.createServer((request, response)=>{ 6 | const {url} = request; 7 | if(url === "/"){ 8 | response.write("

Home page

"); 9 | } else if(url === "/contacts") { 10 | response.write("

Contacts page

"); 11 | } else { 12 | response.write("

Not found

"); 13 | } 14 | response.end(); 15 | }) 16 | 17 | // const server = http.createServer((request, response)=>{ 18 | // // console.log(request.url); 19 | // // console.log(request.headers["user-agent"]); 20 | // // console.log(request.method); 21 | 22 | // response.write("

Добро пожаловать на наш сайт!

"); 23 | // response.end(); 24 | // }); 25 | 26 | server.listen(3000, ()=> { 27 | console.log("Сервер запущен!"); 28 | }); -------------------------------------------------------------------------------- /lesson-3/http-server-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http-server-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "nodemon": "^2.0.7" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lesson-3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-3/slides/Client-Server-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/Client-Server-schema.jpg -------------------------------------------------------------------------------- /lesson-3/slides/fullstack-developer-cors-problem-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/fullstack-developer-cors-problem-2.jpg -------------------------------------------------------------------------------- /lesson-3/slides/fullstack-developer-cors-problem.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/fullstack-developer-cors-problem.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema-details-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/middleware-work-schema-details-2.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema-details-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/middleware-work-schema-details-3.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema-details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/middleware-work-schema-details.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/middleware-work-schema.jpg -------------------------------------------------------------------------------- /lesson-3/slides/what-is-it-cors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-3/slides/what-is-it-cors.jpg -------------------------------------------------------------------------------- /lesson-4/README.md: -------------------------------------------------------------------------------- 1 | [Схема взаимодействия клиента и сервера](./slides/Client-Server-schema.jpg) 2 | 3 | [Как работают middleware в express](./slides/middleware-work-schema.jpg) 4 | 5 | [Как работают middleware в express](./slides/middleware-work-schema.jpg) 6 | 7 | [Более подробно - как работают middleware в express](./slides/middleware-work-schema-details.jpg) 8 | 9 | [Middleware в express как оглавление записной книжки](./slides/middleware-work-schema-details-2.jpg) 10 | 11 | [Middleware в express как набор обязательных действий на ресепшен](./slides/middleware-work-schema-details-3.jpg) 12 | 13 | [Что такое CORS - кросс-доменные запросы](./slides/what-is-it-cors.jpg) 14 | 15 | [Проблемы с CORS при разработки одновремено фронтенда и бекенда](./slides/fullstack-developer-cors-problem.jpg) 16 | 17 | [Проблемы с CORS когда бекенд задеплоен на удаленный сервер](./slides/fullstack-developer-cors-problem-2.jpg) -------------------------------------------------------------------------------- /lesson-4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-4/joi-example/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .idea/ 3 | package-lock.json 4 | yarn.lock 5 | yarn.error 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-4/joi-example/app.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | 3 | const productJoiSchema = Joi.object({ 4 | name: Joi.string().min(1).required(), 5 | price: Joi.number().min(0.01).required(), 6 | location: Joi.string().min(1).required(), 7 | }); 8 | 9 | const product = { 10 | "name": "iPhone X", 11 | "price": 17000, 12 | // "location": "Apple store" 13 | }; 14 | 15 | const {error} = productJoiSchema.validate(product); 16 | if(error){ 17 | console.log(error.message) 18 | } 19 | -------------------------------------------------------------------------------- /lesson-4/joi-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "joi-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "joi": "^17.4.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: ['standard'], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | }, 11 | rules: { 12 | 'comma-dangle': 'off', 13 | 'space-before-function-paren': 'off', 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | 5 | const productsRouter = require('./routes/api/products') 6 | 7 | const app = express() 8 | 9 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 10 | 11 | app.use(logger(formatsLogger)) 12 | app.use(cors()) 13 | app.use(express.json()) 14 | 15 | app.use('/api/products', productsRouter); 16 | 17 | // api/product 18 | app.use((req, res) => { 19 | res.status(404).json({ 20 | status: "error", 21 | message: 'Not found' 22 | }) 23 | }) 24 | 25 | app.use((err, req, res, next) => { 26 | const {status = 500, message = "Server error"} = err; 27 | res.status(status).json({ message }) 28 | }); 29 | 30 | module.exports = app 31 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/bin/server.js: -------------------------------------------------------------------------------- 1 | const app = require('../app') 2 | // console.log(process.env); 3 | // const PORT = process.env.PORT || 3000 4 | const {PORT = 3000} = process.env; 5 | 6 | app.listen(PORT, () => { 7 | console.log(`Server running. Use our API on port: ${PORT}`) 8 | }) 9 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | 3 | module.exports = { 4 | products 5 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/controllers/products.js: -------------------------------------------------------------------------------- 1 | const {NotFound} = require("http-errors"); 2 | 3 | const {sendSuccessRes} = require("../helpers"); 4 | const productsOperations = require("../model/products"); 5 | 6 | const getAll = async(req, res)=> { 7 | const result = await productsOperations.getAll(); 8 | sendSuccessRes(res, {result}); 9 | // res.json({ 10 | // status: "success", 11 | // code: 200, 12 | // data: { 13 | // result: products 14 | // } 15 | // }); 16 | }; 17 | 18 | const getById = async(req, res)=> { 19 | const {id} = req.params; 20 | const result = await productsOperations.getById(id); 21 | if(!result){ 22 | throw new NotFound(`Product with id=${id} not found`); 23 | } 24 | sendSuccessRes(res, {result}); 25 | } 26 | 27 | const add = async(req, res)=>{ 28 | const result = await productsOperations.add(req.body); 29 | sendSuccessRes(res, {result}, 201); 30 | } 31 | 32 | const updateById = async(req, res)=> { 33 | const {id} = req.params; 34 | const result = await productsOperations.updateById(id, req.body); 35 | if(!result){ 36 | throw new NotFound(`Product with id=${id} not found`); 37 | } 38 | sendSuccessRes(res, {result}); 39 | } 40 | 41 | const removeById = async(req, res, next)=>{ 42 | const {id} = req.params; 43 | const result = await productsOperations.removeById(id); 44 | if(!result){ 45 | throw new NotFound(`Product with id=${id} not found`); 46 | } 47 | sendSuccessRes(res, {message: "Success delete"}); 48 | }; 49 | 50 | module.exports = { 51 | getAll, 52 | getById, 53 | add, 54 | updateById, 55 | removeById 56 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = require("./sendSuccessRes"); 2 | 3 | module.exports = { 4 | sendSuccessRes 5 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/helpers/sendSuccessRes.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = (res, data, status = 200)=> { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | } 8 | 9 | module.exports = sendSuccessRes -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl) => { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch(error){ 7 | next(error); 8 | } 9 | } 10 | }; 11 | 12 | module.exports = controllerWrapper -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = require("./controllerWrapper"); 2 | const validation = require("./validation"); 3 | 4 | module.exports = { 5 | controllerWrapper, 6 | validation 7 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema) => { 2 | return async(req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | res.status(400).json({ 6 | status: "error", 7 | code: 400, 8 | message: error.message 9 | }); 10 | return; 11 | } 12 | next(); 13 | } 14 | }; 15 | 16 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/add.js: -------------------------------------------------------------------------------- 1 | const {v4} = require("uuid"); 2 | 3 | const updateProducts = require("./updateProducts"); 4 | const getAll = require("./getAll"); 5 | 6 | const add = async(data) => { 7 | const products = await getAll(); 8 | const newProduct = {...data, id: v4()}; 9 | products.push(newProduct); 10 | // const newProducts = [...products, newProduct]; 11 | await updateProducts(products); 12 | // await updateProducts(newProducts); 13 | return newProduct; 14 | } 15 | 16 | module.exports = add; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/getAll.js: -------------------------------------------------------------------------------- 1 | const products = require("./products.json"); 2 | /* 3 | const data = fs.readFileSync("./products.json"); 4 | const products = JSON.parse(data); 5 | */ 6 | const getAll = async() => products; 7 | 8 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/getById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | 3 | const getById = async(id) => { 4 | const products = await getAll(); 5 | const product = products.find(item => item.id === id); 6 | if(!product) { 7 | return null; 8 | } 9 | return product; 10 | } 11 | 12 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/index.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const getById = require("./getById"); 3 | const add = require("./add"); 4 | const updateById = require("./updateById"); 5 | const removeById = require("./removeById"); 6 | 7 | module.exports = { 8 | getAll, 9 | getById, 10 | add, 11 | updateById, 12 | removeById 13 | } 14 | 15 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/products.json: -------------------------------------------------------------------------------- 1 | [{"id":"48bd1cd8-72ca-42cc-8457-156bb8c30873","name":"cheese","price":2.5,"location":"Refrigerated foods"},{"id":"61c0169c-e693-4a20-af3e-2e55fdc34f79","name":"Crisps","price":4,"location":"the Snack isle"},{"id":"2c9c3d67-07b3-4ee1-a59f-67d54427d3c3","name":"Pizza","price":4,"location":"Refrigerated foods"},{"id":"2386a63f-140a-494c-b4e5-b23a219bbac0","name":"Chocolate","price":1.5,"location":"the Snack isle"},{"id":"8263b539-c546-4a64-866d-97d58e42c585","name":"Self-raising flour","price":1.5,"location":"Home baking"},{"id":"767580d5-f509-4f45-98f9-28e74ec4af66","name":"Ground almonds","price":4,"location":"Home baking"}] -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/removeById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 3 | 4 | const removeById = async(id) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1) { 8 | return null; 9 | } 10 | // const newProducts = products.filter(item => item.id !== id); 11 | products.splice(idx, 1); 12 | await updateProducts(products); 13 | // await updateProducts(newProducts); 14 | return "Success remove" 15 | } 16 | 17 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/updateById.js: -------------------------------------------------------------------------------- 1 | const updateProducts = require("./updateProducts"); 2 | const getAll = require("./getAll"); 3 | 4 | const updateById = async(id, data) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1){ 8 | return null; 9 | } 10 | const updateProduct = {...products[idx], ...data}; 11 | products[idx] = updateProduct; 12 | await updateProducts(products); 13 | return updateProduct; 14 | }; 15 | 16 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | const filePath = path.join(__dirname, "products.json"); 5 | 6 | const updateProducts = async(newProducts) => { 7 | await fs.writeFile(filePath, JSON.stringify(newProducts)); 8 | }; 9 | 10 | module.exports = updateProducts; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template-2", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "cross-env NODE_ENV=production node ./bin/server.js", 7 | "start:dev": "cross-env NODE_ENV=development nodemon ./bin/server.js", 8 | "lint": "eslint **/*.js", 9 | "lint:fix": "eslint --fix **/*.js" 10 | }, 11 | "dependencies": { 12 | "cors": "2.8.5", 13 | "cross-env": "7.0.3", 14 | "express": "4.17.1", 15 | "http-errors": "^1.8.0", 16 | "joi": "^17.4.2", 17 | "morgan": "1.10.0", 18 | "uuid": "^8.3.2" 19 | }, 20 | "devDependencies": { 21 | "eslint": "^7.19.0", 22 | "eslint-config-standard": "^16.0.2", 23 | "eslint-plugin-import": "^2.22.1", 24 | "eslint-plugin-node": "^11.1.0", 25 | "eslint-plugin-promise": "^4.2.1", 26 | "nodemon": "2.0.7" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/readme.md: -------------------------------------------------------------------------------- 1 | ## GoIT Node.js Course Template Homework 2 | 3 | Выполните форк этого репозитория для выполнения домашних заданий (2-6) 4 | Форк создаст репозиторий на вашем http://github.com 5 | 6 | Добавьте ментора в коллаборацию 7 | 8 | Для каждой домашней работы создавайте свою ветку. 9 | 10 | - hw02 11 | - hw03 12 | - hw04 13 | - hw05 14 | - hw06 15 | 16 | Каждая новая ветка для дз должна делаться с master 17 | 18 | После того как вы закончили выполнять домашнее задание в своей ветке, необходимо сделать пулл-реквест (PR). Потом добавить ментора для ревью кода. Только после того как ментор заапрувит PR, вы можете выполнить мердж ветки с домашним заданием в мастер. 19 | 20 | Внимательно читайте комментарии ментора. Исправьте замечания и сделайте коммит в ветке с домашним заданием. Изменения подтянуться в PR автоматически после того как вы отправите коммит с исправлениями на github 21 | После исправления снова добавьте ментора на ревью кода. 22 | 23 | - При сдаче домашней работы есть ссылка на PR 24 | - JS-код чистый и понятный, для форматирования используется Prettier 25 | 26 | ### Команды: 27 | 28 | - `npm start` — старт сервера в режиме production 29 | - `npm run start:dev` — старт сервера в режиме разработки (development) 30 | - `npm run lint` — запустить выполнение проверки кода с eslint, необходимо выполнять перед каждым PR и исправлять все ошибки линтера 31 | - `npm lint:fix` — та же проверка линтера, но с автоматическими исправлениями простых ошибок 32 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {productSchema} = require("../../schemas"); 4 | const {controllerWrapper, validation} = require("../../middlewares"); 5 | const {products: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | /* 10 | 1. Получить все товары. 11 | 2. Получить один товар по id. 12 | 3. Добавить товар. 13 | 4. Обновить товар по id. 14 | 5. Удалить товар по id. 15 | */ 16 | 17 | router.get("/", controllerWrapper(ctrl.getAll)); 18 | 19 | router.get("/:id", controllerWrapper(ctrl.getById)); 20 | 21 | router.post("/", validation(productSchema), controllerWrapper(ctrl.add)); 22 | 23 | router.put("/:id", validation(productSchema), controllerWrapper(ctrl.updateById)); 24 | 25 | router.delete("/:id", controllerWrapper(ctrl.removeById)); 26 | 27 | module.exports = router; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/schemas/index.js: -------------------------------------------------------------------------------- 1 | const productSchema = require("./product"); 2 | 3 | module.exports = { 4 | productSchema 5 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/schemas/product.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | 3 | const productSchema = Joi.object({ 4 | name: Joi.string().min(1).required(), 5 | price: Joi.number().min(0.01).required(), 6 | location: Joi.string().min(1).required(), 7 | }); 8 | 9 | module.exports = productSchema; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: ['standard'], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | }, 11 | rules: { 12 | 'comma-dangle': 'off', 13 | 'space-before-function-paren': 'off', 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | 5 | const productsRouter = require('./routes/api/products') 6 | 7 | const app = express() 8 | 9 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 10 | 11 | app.use(logger(formatsLogger)) 12 | app.use(cors()) 13 | app.use(express.json()) 14 | 15 | app.use('/api/products', productsRouter); 16 | 17 | // api/product 18 | app.use((req, res) => { 19 | res.status(404).json({ 20 | status: "error", 21 | message: 'Not found' 22 | }) 23 | }) 24 | 25 | app.use((err, req, res, next) => { 26 | const {status = 500, message = "Server error"} = err; 27 | res.status(status).json({ message }) 28 | }); 29 | 30 | module.exports = app 31 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/bin/server.js: -------------------------------------------------------------------------------- 1 | const app = require('../app') 2 | // console.log(process.env); 3 | // const PORT = process.env.PORT || 3000 4 | const {PORT = 3000} = process.env; 5 | 6 | app.listen(PORT, () => { 7 | console.log(`Server running. Use our API on port: ${PORT}`) 8 | }) 9 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/add.js: -------------------------------------------------------------------------------- 1 | const {v4} = require("uuid"); 2 | 3 | const updateProducts = require("./updateProducts"); 4 | const getAll = require("./getAll"); 5 | 6 | const add = async(data) => { 7 | const products = await getAll(); 8 | const newProduct = {...data, id: v4()}; 9 | products.push(newProduct); 10 | // const newProducts = [...products, newProduct]; 11 | await updateProducts(products); 12 | // await updateProducts(newProducts); 13 | return newProduct; 14 | } 15 | 16 | module.exports = add; 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/getAll.js: -------------------------------------------------------------------------------- 1 | const products = require("./products.json"); 2 | /* 3 | const data = fs.readFileSync("./products.json"); 4 | const products = JSON.parse(data); 5 | */ 6 | const getAll = async() => products; 7 | 8 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/getById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | 3 | const getById = async(id) => { 4 | const products = await getAll(); 5 | const product = products.find(item => item.id === id); 6 | if(!product) { 7 | return null; 8 | } 9 | return product; 10 | } 11 | 12 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/index.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const getById = require("./getById"); 3 | const add = require("./add"); 4 | const updateById = require("./updateById"); 5 | const removeById = require("./removeById"); 6 | 7 | module.exports = { 8 | getAll, 9 | getById, 10 | add, 11 | updateById, 12 | removeById 13 | } 14 | 15 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/products.json: -------------------------------------------------------------------------------- 1 | [{"id":"48bd1cd8-72ca-42cc-8457-156bb8c30873","name":"cheese","price":2.5,"location":"Refrigerated foods"},{"id":"61c0169c-e693-4a20-af3e-2e55fdc34f79","name":"Crisps","price":4,"location":"the Snack isle"},{"id":"2c9c3d67-07b3-4ee1-a59f-67d54427d3c3","name":"Pizza","price":4,"location":"Refrigerated foods"},{"id":"2386a63f-140a-494c-b4e5-b23a219bbac0","name":"Chocolate","price":1.5,"location":"the Snack isle"},{"id":"8263b539-c546-4a64-866d-97d58e42c585","name":"Self-raising flour","price":1.5,"location":"Home baking"},{"id":"767580d5-f509-4f45-98f9-28e74ec4af66","name":"Ground almonds","price":4,"location":"Home baking"}] -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/removeById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 3 | 4 | const removeById = async(id) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1) { 8 | return null; 9 | } 10 | // const newProducts = products.filter(item => item.id !== id); 11 | products.splice(idx, 1); 12 | await updateProducts(products); 13 | // await updateProducts(newProducts); 14 | return "Success remove" 15 | } 16 | 17 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/updateById.js: -------------------------------------------------------------------------------- 1 | const updateProducts = require("./updateProducts"); 2 | const getAll = require("./getAll"); 3 | 4 | const updateById = async(id, data) => { 5 | const products = await getAll(); 6 | const idx = products.findIndex(item => item.id === id); 7 | if(idx === -1){ 8 | return null; 9 | } 10 | const updateProduct = {...products[idx], ...data}; 11 | products[idx] = updateProduct; 12 | await updateProducts(products); 13 | return updateProduct; 14 | }; 15 | 16 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | const filePath = path.join(__dirname, "products.json"); 5 | 6 | const updateProducts = async(newProducts) => { 7 | await fs.writeFile(filePath, JSON.stringify(newProducts)); 8 | }; 9 | 10 | module.exports = updateProducts; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "cross-env NODE_ENV=production node ./bin/server.js", 7 | "start:dev": "cross-env NODE_ENV=development nodemon ./bin/server.js", 8 | "lint": "eslint **/*.js", 9 | "lint:fix": "eslint --fix **/*.js" 10 | }, 11 | "dependencies": { 12 | "cors": "2.8.5", 13 | "cross-env": "7.0.3", 14 | "express": "4.17.1", 15 | "joi": "^17.4.2", 16 | "morgan": "1.10.0", 17 | "uuid": "^8.3.2" 18 | }, 19 | "devDependencies": { 20 | "eslint": "^7.19.0", 21 | "eslint-config-standard": "^16.0.2", 22 | "eslint-plugin-import": "^2.22.1", 23 | "eslint-plugin-node": "^11.1.0", 24 | "eslint-plugin-promise": "^4.2.1", 25 | "nodemon": "2.0.7" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/readme.md: -------------------------------------------------------------------------------- 1 | ## GoIT Node.js Course Template Homework 2 | 3 | Выполните форк этого репозитория для выполнения домашних заданий (2-6) 4 | Форк создаст репозиторий на вашем http://github.com 5 | 6 | Добавьте ментора в коллаборацию 7 | 8 | Для каждой домашней работы создавайте свою ветку. 9 | 10 | - hw02 11 | - hw03 12 | - hw04 13 | - hw05 14 | - hw06 15 | 16 | Каждая новая ветка для дз должна делаться с master 17 | 18 | После того как вы закончили выполнять домашнее задание в своей ветке, необходимо сделать пулл-реквест (PR). Потом добавить ментора для ревью кода. Только после того как ментор заапрувит PR, вы можете выполнить мердж ветки с домашним заданием в мастер. 19 | 20 | Внимательно читайте комментарии ментора. Исправьте замечания и сделайте коммит в ветке с домашним заданием. Изменения подтянуться в PR автоматически после того как вы отправите коммит с исправлениями на github 21 | После исправления снова добавьте ментора на ревью кода. 22 | 23 | - При сдаче домашней работы есть ссылка на PR 24 | - JS-код чистый и понятный, для форматирования используется Prettier 25 | 26 | ### Команды: 27 | 28 | - `npm start` — старт сервера в режиме production 29 | - `npm run start:dev` — старт сервера в режиме разработки (development) 30 | - `npm run lint` — запустить выполнение проверки кода с eslint, необходимо выполнять перед каждым PR и исправлять все ошибки линтера 31 | - `npm lint:fix` — та же проверка линтера, но с автоматическими исправлениями простых ошибок 32 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/schemas/index.js: -------------------------------------------------------------------------------- 1 | const productSchema = require("./product"); 2 | 3 | module.exports = { 4 | productSchema 5 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/schemas/product.js: -------------------------------------------------------------------------------- 1 | const Joi = require("joi"); 2 | 3 | const productSchema = Joi.object({ 4 | name: Joi.string().min(1).required(), 5 | price: Joi.number().min(0.01).required(), 6 | location: Joi.string().min(1).required(), 7 | }); 8 | 9 | module.exports = productSchema; -------------------------------------------------------------------------------- /lesson-4/slides/CRUD.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/CRUD.jpg -------------------------------------------------------------------------------- /lesson-4/slides/Client-Server-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/Client-Server-schema.jpg -------------------------------------------------------------------------------- /lesson-4/slides/HTTP-methods.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/HTTP-methods.jpg -------------------------------------------------------------------------------- /lesson-4/slides/REST-API-additional-rules.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/REST-API-additional-rules.jpg -------------------------------------------------------------------------------- /lesson-4/slides/REST-API-basic-rules.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/REST-API-basic-rules.jpg -------------------------------------------------------------------------------- /lesson-4/slides/Server-response-code.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/Server-response-code.jpg -------------------------------------------------------------------------------- /lesson-4/slides/middleware-work-schema-details-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/middleware-work-schema-details-2.jpg -------------------------------------------------------------------------------- /lesson-4/slides/middleware-work-schema-details-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/middleware-work-schema-details-3.jpg -------------------------------------------------------------------------------- /lesson-4/slides/middleware-work-schema-details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/middleware-work-schema-details.jpg -------------------------------------------------------------------------------- /lesson-4/slides/middleware-work-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/middleware-work-schema.jpg -------------------------------------------------------------------------------- /lesson-4/slides/old-routes-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/old-routes-example.jpg -------------------------------------------------------------------------------- /lesson-4/slides/what-is-it-cors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-4/slides/what-is-it-cors.jpg -------------------------------------------------------------------------------- /lesson-5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 38 | 44 | 45 | 48 | 49 | -------------------------------------------------------------------------------- /lesson-5/mongodb-project/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | yarn.log 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-5/mongodb-project/app.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | require("dotenv").config(); 3 | 4 | const {Category} = require("./models"); 5 | 6 | const {DB_HOST} = process.env; 7 | 8 | const newCategory = { 9 | name: "tablets", 10 | description: "Самый широкий выбор планшетов!", 11 | image: "./category.jpg" 12 | }; 13 | 14 | mongoose.connect(DB_HOST, { 15 | useNewUrlParser: true, 16 | useUnifiedTopology: true 17 | }) 18 | .then(async()=> { 19 | try { 20 | const result = await Category.create(newCategory); 21 | console.log(result); 22 | } catch (error) { 23 | console.log(error.message) 24 | } 25 | // Category.create(newCategory, (error, data)=>{ 26 | // console.log(error); 27 | // console.log(data); 28 | // }); 29 | // console.log("Database connect success"); 30 | }) 31 | .catch(error => { 32 | console.log(error.message); 33 | }) -------------------------------------------------------------------------------- /lesson-5/mongodb-project/models/category.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | 3 | const categorySchema = Schema({ 4 | name: String, 5 | description: String 6 | }); 7 | 8 | const Category = model("category", categorySchema); 9 | 10 | module.exports = Category; 11 | -------------------------------------------------------------------------------- /lesson-5/mongodb-project/models/index.js: -------------------------------------------------------------------------------- 1 | const Category = require("./category"); 2 | 3 | module.exports = { 4 | Category 5 | } -------------------------------------------------------------------------------- /lesson-5/mongodb-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "dotenv": "^10.0.0", 20 | "express": "^4.17.1", 21 | "mongoose": "^6.0.7" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lesson-5/process-env-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules/ -------------------------------------------------------------------------------- /lesson-5/process-env-example/app.js: -------------------------------------------------------------------------------- 1 | const dotenv = require("dotenv"); 2 | dotenv.config(); 3 | console.log(process.env.DB_HOST); -------------------------------------------------------------------------------- /lesson-5/process-env-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "dotenv": "^10.0.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lesson-5/readme.md: -------------------------------------------------------------------------------- 1 | [Какие бывают варианты размещения сайта на хостинге](./slides/deploy-variants.jpg) 2 | 3 | [Как разместить сайт на одном сервере](./slides/variants-deploy-all-in-one.jpg) 4 | 5 | [Структура бекенда](./slides/backend-structure.jpg) 6 | 7 | [Какие типы баз данных бывают](./slides/database-types.jpg) 8 | 9 | [Почему noSQL базы называают документоориентированными](./slides/documents-database-schema.jpg) 10 | 11 | [Какие типы баз данных бывают](./slides/database-types.jpg) 12 | 13 | [Почему нужно использовать удаленную базу данных](./slides/remote-database.jpg) 14 | 15 | [Как работает пакет dotenv](./slides/dotenv-work-schema.jpg) 16 | 17 | [Как работает бекенд с Google таблицами](./slides/woork-with-google-sheets.jpg) 18 | 19 | [Пример структуры 'схема-модель-коллекция' в жизни](./slides/schema-model-example.jpg) 20 | 21 | [Схема-Модель-коллекцция в MongoDB](./slides/schema-model-collection.jpg) 22 | 23 | 24 | -------------------------------------------------------------------------------- /lesson-5/slides/backend-structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/backend-structure.jpg -------------------------------------------------------------------------------- /lesson-5/slides/database-types.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/database-types.jpg -------------------------------------------------------------------------------- /lesson-5/slides/documents-database-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/documents-database-schema.jpg -------------------------------------------------------------------------------- /lesson-5/slides/dotenv-work-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/dotenv-work-schema.jpg -------------------------------------------------------------------------------- /lesson-5/slides/mongodb-database-structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/mongodb-database-structure.jpg -------------------------------------------------------------------------------- /lesson-5/slides/remote-database.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/remote-database.jpg -------------------------------------------------------------------------------- /lesson-5/slides/schema-model-collection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/schema-model-collection.jpg -------------------------------------------------------------------------------- /lesson-5/slides/schema-model-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-5/slides/schema-model-example.jpg -------------------------------------------------------------------------------- /lesson-6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 38 | 44 | 45 | 48 | 49 | -------------------------------------------------------------------------------- /lesson-6/mongodb-project/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | yarn.log 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-6/mongodb-project/app.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | require("dotenv").config(); 3 | 4 | const {DB_HOST} = process.env; 5 | 6 | mongoose.connect(DB_HOST, { 7 | useNewUrlParser: true, 8 | useUnifiedTopology: true 9 | }) 10 | .then(()=> { 11 | 12 | }) 13 | .catch(error => { 14 | console.log(error.message); 15 | }) -------------------------------------------------------------------------------- /lesson-6/mongodb-project/models/category.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | 3 | const categorySchema = Schema({ 4 | name: String, 5 | description: String 6 | }); 7 | 8 | const Category = model("category", categorySchema); 9 | 10 | module.exports = Category; 11 | -------------------------------------------------------------------------------- /lesson-6/mongodb-project/models/index.js: -------------------------------------------------------------------------------- 1 | const Category = require("./category"); 2 | 3 | module.exports = { 4 | Category 5 | } -------------------------------------------------------------------------------- /lesson-6/mongodb-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "dotenv": "^10.0.0", 20 | "express": "^4.17.1", 21 | "mongoose": "^6.0.7" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.fbkoo.mongodb.net/online_shop?retryWrites=true&w=majority -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | commonjs: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: ['standard'], 8 | parserOptions: { 9 | ecmaVersion: 12, 10 | }, 11 | rules: { 12 | 'comma-dangle': 'off', 13 | 'space-before-function-paren': 'off', 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | 5 | const productsRouter = require('./routes/api/products') 6 | 7 | const app = express() 8 | 9 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 10 | 11 | app.use(logger(formatsLogger)) 12 | app.use(cors()) 13 | app.use(express.json()) 14 | 15 | app.use('/api/products', productsRouter); 16 | 17 | // api/product 18 | app.use((req, res) => { 19 | res.status(404).json({ 20 | status: "error", 21 | message: 'Not found' 22 | }) 23 | }) 24 | 25 | app.use((err, req, res, next) => { 26 | const {status = 500, message = "Server error"} = err; 27 | res.status(status).json({ message }) 28 | }); 29 | 30 | module.exports = app 31 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/bin/server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | require("dotenv").config(); 3 | 4 | const app = require('../app'); 5 | 6 | const {DB_HOST, PORT = 3000} = process.env; 7 | 8 | mongoose.connect(DB_HOST, { 9 | useNewUrlParser: true, 10 | useUnifiedTopology: true 11 | }) 12 | .then(()=> app.listen(PORT)) 13 | .catch(error => { 14 | console.log(error.message); 15 | process.exit(1); 16 | }) 17 | 18 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | 3 | module.exports = { 4 | products 5 | } -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = require("./sendSuccessRes"); 2 | 3 | module.exports = { 4 | sendSuccessRes 5 | } -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/helpers/sendSuccessRes.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = (res, data, status = 200)=> { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | } 8 | 9 | module.exports = sendSuccessRes -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl) => { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch(error){ 7 | next(error); 8 | } 9 | } 10 | }; 11 | 12 | module.exports = controllerWrapper -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = require("./controllerWrapper"); 2 | const validation = require("./validation"); 3 | 4 | module.exports = { 5 | controllerWrapper, 6 | validation 7 | } -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema) => { 2 | return async(req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | res.status(400).json({ 6 | status: "error", 7 | code: 400, 8 | message: error.message 9 | }); 10 | return; 11 | } 12 | next(); 13 | } 14 | }; 15 | 16 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | 3 | module.exports = { 4 | Product 5 | } -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/models/product.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | 4 | const codeRegexp = /^[0-9]{9}$/; // newRegexp("^[0-9]{9}$") 5 | 6 | const productSchema = Schema({ 7 | name: { 8 | type: String, 9 | required: [true, "Название товара обязательно"] 10 | }, 11 | price: { 12 | type: Number, 13 | required: [true, "Цена товара обязательно"], 14 | min: 0.01 15 | }, 16 | code: { 17 | type: String, 18 | unique: true, 19 | match: codeRegexp 20 | }, 21 | active: { 22 | type: Boolean, 23 | default: true 24 | } 25 | }, {versionKey: false, timestamps: true}); 26 | 27 | const joiSchema = Joi.object({ 28 | name: Joi.string().required(), 29 | price:Joi.number().min(0.01).required(), 30 | code: Joi.string().pattern(codeRegexp).required(), 31 | active: Joi.boolean() 32 | }); 33 | 34 | const updateActiveJoiSchema = Joi.object({ 35 | active: Joi.boolean().required() 36 | }); 37 | 38 | const Product = model("product", productSchema); 39 | 40 | module.exports = { 41 | joiSchema, 42 | updateActiveJoiSchema, 43 | Product 44 | }; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template-2", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "cross-env NODE_ENV=production node ./bin/server.js", 7 | "start:dev": "cross-env NODE_ENV=development nodemon ./bin/server.js", 8 | "lint": "eslint **/*.js", 9 | "lint:fix": "eslint --fix **/*.js" 10 | }, 11 | "dependencies": { 12 | "cors": "2.8.5", 13 | "cross-env": "7.0.3", 14 | "dotenv": "^10.0.0", 15 | "express": "4.17.1", 16 | "http-errors": "^1.8.0", 17 | "joi": "^17.4.2", 18 | "mongoose": "^6.0.7", 19 | "morgan": "1.10.0" 20 | }, 21 | "devDependencies": { 22 | "eslint": "^7.19.0", 23 | "eslint-config-standard": "^16.0.2", 24 | "eslint-plugin-import": "^2.22.1", 25 | "eslint-plugin-node": "^11.1.0", 26 | "eslint-plugin-promise": "^4.2.1", 27 | "nodemon": "2.0.7" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/readme.md: -------------------------------------------------------------------------------- 1 | ## GoIT Node.js Course Template Homework 2 | 3 | Выполните форк этого репозитория для выполнения домашних заданий (2-6) 4 | Форк создаст репозиторий на вашем http://github.com 5 | 6 | Добавьте ментора в коллаборацию 7 | 8 | Для каждой домашней работы создавайте свою ветку. 9 | 10 | - hw02 11 | - hw03 12 | - hw04 13 | - hw05 14 | - hw06 15 | 16 | Каждая новая ветка для дз должна делаться с master 17 | 18 | После того как вы закончили выполнять домашнее задание в своей ветке, необходимо сделать пулл-реквест (PR). Потом добавить ментора для ревью кода. Только после того как ментор заапрувит PR, вы можете выполнить мердж ветки с домашним заданием в мастер. 19 | 20 | Внимательно читайте комментарии ментора. Исправьте замечания и сделайте коммит в ветке с домашним заданием. Изменения подтянуться в PR автоматически после того как вы отправите коммит с исправлениями на github 21 | После исправления снова добавьте ментора на ревью кода. 22 | 23 | - При сдаче домашней работы есть ссылка на PR 24 | - JS-код чистый и понятный, для форматирования используется Prettier 25 | 26 | ### Команды: 27 | 28 | - `npm start` — старт сервера в режиме production 29 | - `npm run start:dev` — старт сервера в режиме разработки (development) 30 | - `npm run lint` — запустить выполнение проверки кода с eslint, необходимо выполнять перед каждым PR и исправлять все ошибки линтера 31 | - `npm lint:fix` — та же проверка линтера, но с автоматическими исправлениями простых ошибок 32 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {joiSchema, updateActiveJoiSchema} = require("../../models/product"); 4 | const {controllerWrapper, validation} = require("../../middlewares"); 5 | const {products: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | /* 10 | 1. Получить все товары. 11 | 2. Получить один товар по id. 12 | 3. Добавить товар. 13 | 4. Обновить товар по id. 14 | 5. Удалить товар по id. 15 | */ 16 | 17 | router.get("/", controllerWrapper(ctrl.getAll)); 18 | 19 | router.get("/:id", controllerWrapper(ctrl.getById)); 20 | 21 | router.post("/", validation(joiSchema), controllerWrapper(ctrl.add)); 22 | 23 | router.put("/:id", validation(joiSchema), controllerWrapper(ctrl.updateById)); 24 | 25 | router.patch("/:id/active", validation(updateActiveJoiSchema), controllerWrapper(ctrl.updateActive)); 26 | 27 | router.patch("/:id/code", validation(updateActiveJoiSchema), controllerWrapper(ctrl.updateCode)); 28 | 29 | router.delete("/:id", controllerWrapper(ctrl.removeById)); 30 | 31 | module.exports = router; -------------------------------------------------------------------------------- /lesson-6/slides/schema-model-collection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-6/slides/schema-model-collection.jpg -------------------------------------------------------------------------------- /lesson-6/slides/schema-model-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-6/slides/schema-model-example.jpg -------------------------------------------------------------------------------- /lesson-7/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-7/README.md: -------------------------------------------------------------------------------- 1 | [Как HTTP-протокол общается с бекендом](./slides/HTTP-common-schema.jpg) 2 | [Когда ответ на HTTP-запрос должен быть персонализированным](./slides/HTTP-personal-request-schema.jpg) 3 | [Как сделать ответ на HTTP-запрос персонализированным и не логинится при каждом запросе](./slides/frontend-backend-requests-with-token.jpg) 4 | [Разница между регистрацией, аутентификацией и авторизацией](./slides/register-auth-steps.jpg) 5 | [Этапы создания модуля регистрации-аутентфикации-авторизации](./slides/reigster-auth-create-steps.jpg) 6 | [Разница между хэшем и шифрованием](./slides/hash-schema.jpg) 7 | [Работа с переменными окружения на локальном хосте и на удаленном сервере](./slides/process.env-and-deploy.jpg) 8 | -------------------------------------------------------------------------------- /lesson-7/auth-example/.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | SECRET_KEY= -------------------------------------------------------------------------------- /lesson-7/auth-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-7/auth-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | const mongoose = require("mongoose"); 4 | require("dotenv").config(); 5 | 6 | const authRouter = require("./routes/api/auth"); 7 | 8 | const app = express(); 9 | 10 | app.use(cors()); 11 | app.use(express.json()); 12 | 13 | app.use("/api/auth", authRouter); 14 | 15 | app.use((req, res)=>{ 16 | res.status(404).json({ 17 | status: "error", 18 | code: 404, 19 | message: "Not Found" 20 | }) 21 | }); 22 | 23 | app.use((error, req, res, next)=>{ 24 | const {status = 500, message = "Server error"} = error; 25 | res.status(status).json({ 26 | status: "error", 27 | code: status, 28 | message 29 | }) 30 | }); 31 | 32 | const {DB_HOST, PORT = 3000} = process.env; 33 | // const {DB_USER, DB_USER_PASS, DB_NAME} = process.env; 34 | // const DB_HOST = `mongodb+srv://${DB_USER}:${DB_USER_PASS}@cluster0.fbkoo.mongodb.net/${DB_NAME}?retryWrites=true&w=majority` 35 | 36 | mongoose.connect(DB_HOST, { 37 | useNewUrlParser: true, 38 | useUnifiedTopology: true 39 | }).then(()=> app.listen(PORT)) 40 | .catch(error => { 41 | console.log(error.message); 42 | process.exit(1); 43 | }); -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/auth/index.js: -------------------------------------------------------------------------------- 1 | const register = require("./register"); 2 | const login = require("./login"); 3 | const logout = require("./logout"); 4 | 5 | module.exports = { 6 | register, 7 | login, 8 | logout 9 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/auth/login.js: -------------------------------------------------------------------------------- 1 | const {BadRequest, NotFound} = require("http-errors"); 2 | const bcrypt = require("bcryptjs"); 3 | 4 | const {User} = require("../../models"); 5 | 6 | const login = async(req, res)=>{ 7 | const {email, password} = req.body; 8 | const user = await User.findOne({email}, "_id email password"); 9 | if(!user || !user.comparePassword(password)){ 10 | throw new BadRequest("Invalid email or password"); 11 | } 12 | // if(!user){ 13 | // throw new NotFound(`Email ${email} not found`); 14 | // // res.status(404).json({ 15 | // // status: "error", 16 | // // code: 404, 17 | // // message: `Email ${email} not found` 18 | // // }); 19 | // // return; 20 | // } 21 | // if(!user.comparePassword(password)){ 22 | // throw new BadRequest("Invalid password"); 23 | // } 24 | // if(!bcrypt.compareSync(password, user.password)){ 25 | // throw new BadRequest("Invalid password"); 26 | // // res.status(400).json({ 27 | // // status: "error", 28 | // // code: 400, 29 | // // message: "Invalid password" 30 | // // }); 31 | // // return; 32 | // } 33 | const token = "ghsdfsdfsfg.hsgfdhdghdh.dfgdhdhsdsasa"; 34 | res.json({ 35 | status: "success", 36 | code: 200, 37 | data: { 38 | token 39 | } 40 | }) 41 | }; 42 | 43 | module.exports = login; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/auth/logout.js: -------------------------------------------------------------------------------- 1 | const {User} = require("../../models"); 2 | 3 | const logout = async(req, res)=>{ 4 | 5 | }; 6 | 7 | module.exports = logout; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/auth/register.js: -------------------------------------------------------------------------------- 1 | const {Conflict} = require("http-errors"); 2 | // const bcrypt = require("bcryptjs"); 3 | 4 | const {User} = require("../../models"); 5 | 6 | const register = async(req, res)=>{ 7 | const {email, password} = req.body; 8 | const user = await User.findOne({email}); 9 | if(user){ 10 | throw new Conflict("Already register"); 11 | // res.status(409).json({ 12 | // status: "error", 13 | // code: 409, 14 | // message: "Already register" 15 | // }); 16 | // return; 17 | } 18 | const newUser = new User({email}); 19 | // newUser = {email} 20 | newUser.setPassword(password); 21 | // newUser = {email, password} 22 | await newUser.save(); 23 | // const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 24 | // const newUser = {email, password: hashPassword}; 25 | // await User.create(newUser); 26 | res.status(201).json({ 27 | status: "success", 28 | code: 201, 29 | message: "Success register" 30 | }) 31 | }; 32 | 33 | module.exports = register; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/index.js: -------------------------------------------------------------------------------- 1 | const auth = require("./auth"); 2 | 3 | module.exports = { 4 | auth 5 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = require("./sendSuccessRes"); 2 | 3 | module.exports = { 4 | sendSuccessRes 5 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/helpers/sendSuccessRes.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = (res, data, status = 200)=> { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | } 8 | 9 | module.exports = sendSuccessRes -------------------------------------------------------------------------------- /lesson-7/auth-example/models/index.js: -------------------------------------------------------------------------------- 1 | const {User} = require("./user"); 2 | 3 | module.exports = { 4 | User 5 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/models/user.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | const bcrypt = require("bcryptjs"); 4 | 5 | const userSchema = Schema({ 6 | email: { 7 | type: String, 8 | required: true, 9 | unique: true 10 | }, 11 | password: { 12 | type: String, 13 | required: true, 14 | minlength: 6 15 | } 16 | }, {versionKey: false, timestamps: true}); 17 | 18 | userSchema.methods.setPassword = function(password){ 19 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)) 20 | } 21 | 22 | userSchema.methods.comparePassword = function(password){ 23 | return bcrypt.compareSync(password, this.password); 24 | } 25 | 26 | const joiSchema = Joi.object({ 27 | email: Joi.string().required(), 28 | password: Joi.string().min(6).required() 29 | }); 30 | 31 | const User = model("user", userSchema); 32 | 33 | module.exports = { 34 | User, 35 | joiSchema 36 | } 37 | -------------------------------------------------------------------------------- /lesson-7/auth-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auth-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "bcryptjs": "^2.4.3", 19 | "cors": "^2.8.5", 20 | "dotenv": "^10.0.0", 21 | "express": "^4.17.1", 22 | "http-errors": "^1.8.0", 23 | "joi": "^17.4.2", 24 | "mongoose": "^6.0.8" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lesson-7/auth-example/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {joiSchema} = require("../../models/user"); 4 | const {controllerWrapper, validation} = require("../../middlewares"); 5 | const {auth: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | /* 10 | 1. Регистраця нового нового пользователя. 11 | 2. Аутентификациия (логин) зарегистрированного пользователя. 12 | 3. Авторизация аутентифицированного (зашедшего на сайт) пользователя. 13 | 4. Выход (Logout). 14 | */ 15 | // api/auth/register 16 | router.post("/register", validation(joiSchema), controllerWrapper(ctrl.register)); 17 | // router.post("/signup") 18 | 19 | router.post("/login", validation(joiSchema), controllerWrapper(ctrl.login)); 20 | // router.post("/signin") 21 | 22 | router.get("/logout", controllerWrapper(ctrl.logout)); 23 | // router.get("/signuot") 24 | 25 | module.exports = router; -------------------------------------------------------------------------------- /lesson-7/hash-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-7/hash-example/app.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require("bcryptjs"); 2 | 3 | const password = "password"; 4 | 5 | const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 6 | // console.log(hashPassword); 7 | 8 | const compareResult = bcrypt.compareSync(password, hashPassword); 9 | // console.log(compareResult); 10 | 11 | const compareResult2 = bcrypt.compareSync("password2", hashPassword); 12 | console.log(compareResult2); -------------------------------------------------------------------------------- /lesson-7/hash-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hash-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "bcryptjs": "^2.4.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-7/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-7/slides/HTTP-common-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/HTTP-common-schema.jpg -------------------------------------------------------------------------------- /lesson-7/slides/HTTP-personal-request-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/HTTP-personal-request-schema.jpg -------------------------------------------------------------------------------- /lesson-7/slides/frontend-backend-requests-with-token.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/frontend-backend-requests-with-token.jpg -------------------------------------------------------------------------------- /lesson-7/slides/hash-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/hash-schema.jpg -------------------------------------------------------------------------------- /lesson-7/slides/jwt-token-real-life-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/jwt-token-real-life-example.jpg -------------------------------------------------------------------------------- /lesson-7/slides/process.env-and-deploy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/process.env-and-deploy.jpg -------------------------------------------------------------------------------- /lesson-7/slides/register-auth-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/register-auth-steps.jpg -------------------------------------------------------------------------------- /lesson-7/slides/reigster-auth-create-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-7/slides/reigster-auth-create-steps.jpg -------------------------------------------------------------------------------- /lesson-8/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-8/README.md: -------------------------------------------------------------------------------- 1 | [Как HTTP-протокол общается с бекендом](./slides/HTTP-common-schema.jpg) 2 | [Когда ответ на HTTP-запрос должен быть персонализированным](./slides/HTTP-personal-request-schema.jpg) 3 | [Как сделать ответ на HTTP-запрос персонализированным и не логинится при каждом запросе](./slides/frontend-backend-requests-with-token.jpg) 4 | [Разница между регистрацией, аутентификацией и авторизацией](./slides/register-auth-steps.jpg) 5 | [Этапы создания модуля регистрации-аутентфикации-авторизации](./slides/reigster-auth-create-steps.jpg) 6 | [Разница между хэшем и шифрованием](./slides/hash-schema.jpg) 7 | [Работа с переменными окружения на локальном хосте и на удаленном сервере](./slides/process.env-and-deploy.jpg) 8 | -------------------------------------------------------------------------------- /lesson-8/auth-example/.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | SECRET_KEY= -------------------------------------------------------------------------------- /lesson-8/auth-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-8/auth-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | const mongoose = require("mongoose"); 4 | require("dotenv").config(); 5 | 6 | const authRouter = require("./routes/api/auth"); 7 | const ordersRouter = require("./routes/api/orders"); 8 | 9 | const app = express(); 10 | 11 | app.use(cors()); 12 | app.use(express.json()); 13 | 14 | app.use("/api/auth", authRouter); 15 | app.use("/api/orders", ordersRouter); 16 | 17 | app.use((req, res)=>{ 18 | res.status(404).json({ 19 | status: "error", 20 | code: 404, 21 | message: "Not Found" 22 | }) 23 | }); 24 | 25 | app.use((error, req, res, next)=>{ 26 | const {status = 500, message = "Server error"} = error; 27 | res.status(status).json({ 28 | status: "error", 29 | code: status, 30 | message 31 | }) 32 | }); 33 | 34 | const {DB_HOST, PORT = 3000} = process.env; 35 | // const {DB_USER, DB_USER_PASS, DB_NAME} = process.env; 36 | // const DB_HOST = `mongodb+srv://${DB_USER}:${DB_USER_PASS}@cluster0.fbkoo.mongodb.net/${DB_NAME}?retryWrites=true&w=majority` 37 | 38 | mongoose.connect(DB_HOST, { 39 | useNewUrlParser: true, 40 | useUnifiedTopology: true 41 | }).then(()=> app.listen(PORT)) 42 | .catch(error => { 43 | console.log(error.message); 44 | process.exit(1); 45 | }); -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/auth/index.js: -------------------------------------------------------------------------------- 1 | const register = require("./register"); 2 | const login = require("./login"); 3 | const logout = require("./logout"); 4 | 5 | module.exports = { 6 | register, 7 | login, 8 | logout 9 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/auth/login.js: -------------------------------------------------------------------------------- 1 | const {BadRequest} = require("http-errors"); 2 | const bcrypt = require("bcryptjs"); 3 | const jwt = require("jsonwebtoken"); 4 | 5 | const {User} = require("../../models"); 6 | 7 | const {SECRET_KEY} = process.env; 8 | 9 | const login = async(req, res)=>{ 10 | const {email, password} = req.body; 11 | const user = await User.findOne({email}, "_id email password"); 12 | if(!user || !user.comparePassword(password)){ 13 | throw new BadRequest("Invalid email or password"); 14 | } 15 | // if(!user){ 16 | // throw new NotFound(`Email ${email} not found`); 17 | // // res.status(404).json({ 18 | // // status: "error", 19 | // // code: 404, 20 | // // message: `Email ${email} not found` 21 | // // }); 22 | // // return; 23 | // } 24 | // if(!user.comparePassword(password)){ 25 | // throw new BadRequest("Invalid password"); 26 | // } 27 | // if(!bcrypt.compareSync(password, user.password)){ 28 | // throw new BadRequest("Invalid password"); 29 | // // res.status(400).json({ 30 | // // status: "error", 31 | // // code: 400, 32 | // // message: "Invalid password" 33 | // // }); 34 | // // return; 35 | // } 36 | const {_id} = user; 37 | const payload = { 38 | _id 39 | } 40 | const token = jwt.sign(payload, SECRET_KEY); 41 | // const token = user.createToken(); 42 | await User.findByIdAndUpdate(_id, {token}); 43 | res.json({ 44 | status: "success", 45 | code: 200, 46 | data: { 47 | token 48 | } 49 | }) 50 | }; 51 | 52 | module.exports = login; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/auth/logout.js: -------------------------------------------------------------------------------- 1 | const {User} = require("../../models"); 2 | 3 | const logout = async(req, res)=>{ 4 | const {_id} = req.user; 5 | await User.findByIdAndUpdate(_id, {token: null}); 6 | res.json({ 7 | status: "success", 8 | code: 200, 9 | message: "Success logout" 10 | }); 11 | }; 12 | 13 | module.exports = logout; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/auth/register.js: -------------------------------------------------------------------------------- 1 | const {Conflict} = require("http-errors"); 2 | // const bcrypt = require("bcryptjs"); 3 | 4 | const {User} = require("../../models"); 5 | 6 | const register = async(req, res)=>{ 7 | const {email, password} = req.body; 8 | const user = await User.findOne({email}); 9 | if(user){ 10 | throw new Conflict("Already register"); 11 | // res.status(409).json({ 12 | // status: "error", 13 | // code: 409, 14 | // message: "Already register" 15 | // }); 16 | // return; 17 | } 18 | const newUser = new User({email}); 19 | // newUser = {email} 20 | newUser.setPassword(password); 21 | // newUser = {email, password} 22 | await newUser.save(); 23 | // const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 24 | // const newUser = {email, password: hashPassword}; 25 | // await User.create(newUser); 26 | res.status(201).json({ 27 | status: "success", 28 | code: 201, 29 | message: "Success register" 30 | }); 31 | }; 32 | 33 | module.exports = register; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/index.js: -------------------------------------------------------------------------------- 1 | const auth = require("./auth"); 2 | const orders = require("./orders"); 3 | 4 | module.exports = { 5 | auth, 6 | orders 7 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/orders/add.js: -------------------------------------------------------------------------------- 1 | const {Order} = require("../../models"); 2 | 3 | const add = async(req, res)=> { 4 | const newOrder = {...req.body, owner: req.user._id}; 5 | const result = await Order.create(newOrder); 6 | res.status(201).json({ 7 | status: "success", 8 | code: 201, 9 | data: { 10 | result 11 | } 12 | }); 13 | }; 14 | 15 | module.exports = add; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/orders/getAll.js: -------------------------------------------------------------------------------- 1 | const {Order} = require("../../models"); 2 | 3 | const getAll = async(req, res)=>{ 4 | const result = await Order.find({}, "_id content owner"); 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | result 10 | } 11 | }) 12 | }; 13 | 14 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/orders/getAllByUser.js: -------------------------------------------------------------------------------- 1 | const {Order} = require("../../models"); 2 | 3 | const getAllByUser = async(req, res)=>{ 4 | const {_id} = req.user; 5 | const result = await Order.find({owner: _id}, "_id content owner"); 6 | res.json({ 7 | status: "success", 8 | code: 200, 9 | data: { 10 | result 11 | } 12 | }) 13 | }; 14 | 15 | module.exports = getAllByUser; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/orders/index.js: -------------------------------------------------------------------------------- 1 | const add = require("./add"); 2 | const getAllByUser = require("./getAllByUser"); 3 | const getAll = require("./getAll"); 4 | 5 | module.exports = { 6 | add, 7 | getAllByUser, 8 | getAll 9 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = require("./sendSuccessRes"); 2 | 3 | module.exports = { 4 | sendSuccessRes 5 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/helpers/sendSuccessRes.js: -------------------------------------------------------------------------------- 1 | const sendSuccessRes = (res, data, status = 200)=> { 2 | res.status(status).json({ 3 | status: "success", 4 | code: status, 5 | data 6 | }); 7 | } 8 | 9 | module.exports = sendSuccessRes -------------------------------------------------------------------------------- /lesson-8/auth-example/middlewares/authenticate.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | 3 | const {User} = require("../models"); 4 | 5 | const {SECRET_KEY} = process.env; 6 | 7 | const authenticate = async(req, res, next) => { 8 | const {authorization} = req.headers; 9 | if(!authorization){ 10 | res.status(401).json({ 11 | status: "error", 12 | code: 401, 13 | message: "Not authorized" 14 | }); 15 | return; 16 | } 17 | 18 | const [bearer, token] = authorization.split(" "); 19 | if(bearer !== "Bearer"){ 20 | res.status(401).json({ 21 | status: "error", 22 | code: 401, 23 | message: "Not authorized" 24 | }); 25 | return; 26 | } 27 | 28 | try { 29 | const {_id} = jwt.verify(token, SECRET_KEY); 30 | const user = await User.findById(_id); 31 | if(!user.token){ 32 | res.status(401).json({ 33 | status: "error", 34 | code: 401, 35 | message: "Not authorized" 36 | }); 37 | return; 38 | } 39 | req.user = user; 40 | next(); 41 | } 42 | catch (error) { 43 | res.status(401).json({ 44 | status: "error", 45 | code: 401, 46 | message: "Not authorized" 47 | }); 48 | return; 49 | } 50 | }; 51 | 52 | module.exports = authenticate; -------------------------------------------------------------------------------- /lesson-8/auth-example/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl) => { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch(error){ 7 | next(error); 8 | } 9 | } 10 | }; 11 | 12 | module.exports = controllerWrapper -------------------------------------------------------------------------------- /lesson-8/auth-example/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = require("./controllerWrapper"); 2 | const validation = require("./validation"); 3 | const authenticate = require("./authenticate"); 4 | 5 | module.exports = { 6 | controllerWrapper, 7 | validation, 8 | authenticate 9 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema) => { 2 | return async(req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | res.status(400).json({ 6 | status: "error", 7 | code: 400, 8 | message: error.message 9 | }); 10 | return; 11 | } 12 | next(); 13 | } 14 | }; 15 | 16 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-8/auth-example/models/index.js: -------------------------------------------------------------------------------- 1 | const {User} = require("./user"); 2 | const {Order} = require("./order"); 3 | 4 | module.exports = { 5 | User, 6 | Order 7 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/models/order.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | 4 | const orderSchema = Schema({ 5 | content: { 6 | type: String, 7 | required: true 8 | }, 9 | owner: { 10 | type: Schema.Types.ObjectId, 11 | ref: "user" 12 | } 13 | }, {versionKey: false, timestamps: true}); 14 | 15 | const joiSchema = Joi.object({ 16 | content: Joi.string().required() 17 | }); 18 | 19 | const Order = model("order", orderSchema); 20 | 21 | module.exports = { 22 | Order, 23 | joiSchema 24 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/models/user.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | const bcrypt = require("bcryptjs"); 4 | const jwt = require("jsonwebtoken"); 5 | 6 | const userSchema = Schema({ 7 | email: { 8 | type: String, 9 | required: true, 10 | unique: true 11 | }, 12 | password: { 13 | type: String, 14 | required: true, 15 | minlength: 6 16 | }, 17 | token: { 18 | type: String, 19 | default: null 20 | } 21 | }, {versionKey: false, timestamps: true}); 22 | 23 | userSchema.methods.setPassword = function(password){ 24 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)) 25 | } 26 | 27 | userSchema.methods.comparePassword = function(password){ 28 | return bcrypt.compareSync(password, this.password); 29 | } 30 | 31 | const {SECRET_KEY} = process.env; 32 | 33 | userSchema.methods.createToken = function(){ 34 | const payload = { 35 | _id: this._id 36 | }; 37 | return jwt.sign(payload, SECRET_KEY) 38 | } 39 | 40 | const joiSchema = Joi.object({ 41 | email: Joi.string().required(), 42 | password: Joi.string().min(6).required() 43 | }); 44 | 45 | const User = model("user", userSchema); 46 | 47 | module.exports = { 48 | User, 49 | joiSchema 50 | } 51 | -------------------------------------------------------------------------------- /lesson-8/auth-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auth-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "bcryptjs": "^2.4.3", 19 | "cors": "^2.8.5", 20 | "dotenv": "^10.0.0", 21 | "express": "^4.17.1", 22 | "http-errors": "^1.8.0", 23 | "joi": "^17.4.2", 24 | "jsonwebtoken": "^8.5.1", 25 | "mongoose": "^6.0.8" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lesson-8/auth-example/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {joiSchema} = require("../../models/user"); 4 | const {controllerWrapper, validation, authenticate} = require("../../middlewares"); 5 | const {auth: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | /* 10 | 1. Регистраця нового нового пользователя. 11 | 2. Аутентификациия (логин) зарегистрированного пользователя. 12 | 3. Авторизация аутентифицированного (зашедшего на сайт) пользователя. 13 | 4. Выход (Logout). 14 | */ 15 | // api/auth/register 16 | router.post("/register", validation(joiSchema), controllerWrapper(ctrl.register)); 17 | // router.post("/signup") 18 | 19 | router.post("/login", validation(joiSchema), controllerWrapper(ctrl.login)); 20 | // router.post("/signin") 21 | 22 | router.get("/logout", authenticate, controllerWrapper(ctrl.logout)); 23 | // router.get("/signuot") 24 | 25 | module.exports = router; -------------------------------------------------------------------------------- /lesson-8/auth-example/routes/api/orders.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {joiSchema} = require("../../models/order"); 4 | const {controllerWrapper, validation, authenticate} = require("../../middlewares"); 5 | const {orders: ctrl} = require("../../controllers"); 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", authenticate, controllerWrapper(ctrl.getAllByUser)); 10 | 11 | router.get("/all", controllerWrapper(ctrl.getAll)); 12 | 13 | router.post("/", authenticate, validation(joiSchema), controllerWrapper(ctrl.add)); 14 | 15 | module.exports = router; -------------------------------------------------------------------------------- /lesson-8/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-8/jsonwebtoken-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-8/jsonwebtoken-example/app.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | 3 | const SECRET_KEY = "fhgsdffhsd"; 4 | 5 | const payload = { 6 | _id: "6154b0ae55bcd821faba0fe9" 7 | }; 8 | 9 | const token = jwt.sign(payload, SECRET_KEY, { expiresIn: '1h' }); 10 | // console.log(token); 11 | 12 | const decodeToken = jwt.decode(token); 13 | // console.log(decodeToken); 14 | 15 | try { 16 | const verifyToken = jwt.verify(`${token}e`, SECRET_KEY); 17 | console.log(verifyToken); 18 | } catch (error) { 19 | console.log(error.message); 20 | } 21 | -------------------------------------------------------------------------------- /lesson-8/jsonwebtoken-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsonwebtoken-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.12" 16 | }, 17 | "dependencies": { 18 | "jsonwebtoken": "^8.5.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-8/slides/JWT-token-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-8/slides/JWT-token-schema.jpg -------------------------------------------------------------------------------- /lesson-8/slides/hash-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-8/slides/hash-schema.jpg -------------------------------------------------------------------------------- /lesson-8/slides/logout-examples.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-8/slides/logout-examples.jpg -------------------------------------------------------------------------------- /lesson-9/README.md: -------------------------------------------------------------------------------- 1 | [Схема работы библиотеки passport](./slides/passport-work-schema.jpg) 2 | 3 | [Схема работы библиотеки multer](./slides/multer-work-schema.jpg) -------------------------------------------------------------------------------- /lesson-9/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | 12 | 13 |
14 | 24 | 25 | -------------------------------------------------------------------------------- /lesson-9/multer-example-2/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.ubani.mongodb.net/online_shop?retryWrites=true&w=majority 2 | SECRET_KEY=ghsdfdfhdsdfsdgsgsdfd -------------------------------------------------------------------------------- /lesson-9/multer-example-2/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-9/multer-example-2/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | const mongoose = require("mongoose"); 4 | require("dotenv").config(); 5 | 6 | const productsRouter = require("./routes/api/products"); 7 | 8 | const app = express(); 9 | 10 | app.use(cors()); 11 | app.use(express.json()); 12 | app.use(express.static("public")); 13 | 14 | app.use("/api/products", productsRouter); 15 | 16 | const {DB_HOST, PORT = 3000} = process.env; 17 | 18 | mongoose.connect(DB_HOST).then(()=> app.listen(PORT)) 19 | .catch(error => { 20 | console.log(error.message); 21 | process.exit(1); 22 | }); 23 | -------------------------------------------------------------------------------- /lesson-9/multer-example-2/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | 3 | module.exports = { 4 | products 5 | } -------------------------------------------------------------------------------- /lesson-9/multer-example-2/controllers/products.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const fs = require("fs/promises"); 3 | 4 | const {Product} = require("../models"); 5 | 6 | const productsDir = path.join( __dirname, "../", "public/products"); 7 | 8 | const add = async(req, res)=>{ 9 | const {path: tempStorage, originalname} = req.file; 10 | try { 11 | const newProduct = { 12 | name: req.body.name, 13 | photo: "/public/products/default.png" 14 | }; 15 | const result = await Product.create(newProduct); 16 | const [extention] = originalname.split(".").reverse(); 17 | const newFileName = `product_main-image_${result._id}.${extention}`; 18 | const resultStorage = path.join(productsDir, newFileName); 19 | await fs.rename(tempStorage, resultStorage); 20 | const photo = path.join("/products", newFileName); 21 | const product = await Product.findByIdAndUpdate(result._id, {photo}, {new: true}); 22 | res.status(201).json({ 23 | result: product 24 | }); 25 | } catch (error) { 26 | await fs.unlink(tempStorage); 27 | throw error; 28 | } 29 | }; 30 | 31 | const getAll = async(req, res)=>{ 32 | const result = await Product.find({}); 33 | res.json( 34 | result 35 | ) 36 | }; 37 | 38 | module.exports = { 39 | add, 40 | getAll 41 | } -------------------------------------------------------------------------------- /lesson-9/multer-example-2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 14 | 34 | 35 | -------------------------------------------------------------------------------- /lesson-9/multer-example-2/middlewares/controllerWrapper.js: -------------------------------------------------------------------------------- 1 | const controllerWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } 6 | catch (error) { 7 | next(error); 8 | } 9 | } 10 | } 11 | 12 | module.exports = controllerWrapper; -------------------------------------------------------------------------------- /lesson-9/multer-example-2/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const upload = require("./upload"); 2 | const controllerWrapper = require("./controllerWrapper"); 3 | 4 | module.exports = { 5 | upload, 6 | controllerWrapper 7 | }; -------------------------------------------------------------------------------- /lesson-9/multer-example-2/middlewares/upload.js: -------------------------------------------------------------------------------- 1 | const multer = require("multer"); 2 | const path = require("path"); 3 | 4 | const tempDir = path.join(__dirname, "../", "temp"); 5 | 6 | const multerSetting = multer.diskStorage({ 7 | destination: (req, file, cb)=>{ 8 | cb(null, tempDir); 9 | }, 10 | filename: (req, file, cb)=>{ 11 | cb(null, file.originalname); 12 | }, 13 | limits: { 14 | fileSize: 2058 15 | } 16 | }); 17 | 18 | const upload = multer({ 19 | storage: multerSetting 20 | }); 21 | 22 | module.exports = upload; -------------------------------------------------------------------------------- /lesson-9/multer-example-2/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | 3 | module.exports = { 4 | Product 5 | } -------------------------------------------------------------------------------- /lesson-9/multer-example-2/models/product.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | 3 | const productSchema = Schema({ 4 | name: { 5 | type: String, 6 | required: true 7 | }, 8 | photo: { 9 | type: String, 10 | required: true 11 | } 12 | }, {versionKey: false, timestamps: true}); 13 | 14 | const Product = model("product", productSchema); 15 | 16 | module.exports = { 17 | Product 18 | } -------------------------------------------------------------------------------- /lesson-9/multer-example-2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multer-example-2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "dotenv": "^10.0.0", 20 | "express": "^4.17.1", 21 | "mongoose": "^6.0.8", 22 | "multer": "^1.4.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lesson-9/multer-example-2/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {upload, controllerWrapper} = require("../../middlewares"); 4 | const {products: ctrl} = require("../../controllers"); 5 | 6 | const router = express.Router(); 7 | 8 | router.post("/", upload.single("photo"), controllerWrapper(ctrl.add)); 9 | 10 | router.get("/", controllerWrapper(ctrl.getAll)); 11 | 12 | module.exports = router; -------------------------------------------------------------------------------- /lesson-9/multer-example/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-9/multer-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | const multer = require("multer"); 4 | const path = require("path"); 5 | const {v4} = require("uuid"); 6 | const fs = require("fs/promises"); 7 | 8 | const tempDir = path.join(__dirname, "temp"); 9 | const uploadDir = path.join(__dirname, "public"); 10 | 11 | const uploadConfig = multer.diskStorage({ 12 | destination: (req, file, cb)=>{ 13 | cb(null, tempDir); 14 | }, 15 | filename: (req, file, cb)=> { 16 | cb(null, file.originalname); 17 | }, 18 | limits: { 19 | fileSize: 2048 20 | } 21 | }); 22 | 23 | const uploadMiddleware = multer({ 24 | storage: uploadConfig 25 | }); 26 | 27 | const app = express(); 28 | 29 | app.use(cors()); 30 | app.use(express.json()); 31 | app.use(express.static("public")); 32 | 33 | const products = []; 34 | 35 | app.post("/api/products", uploadMiddleware.single("image"), async(req, res)=> { 36 | const {originalname, path: tempName} = req.file; 37 | const fileName = path.join(uploadDir, "products", originalname); 38 | try { 39 | await fs.rename(tempName, fileName); 40 | const image = path.join("/products", originalname); 41 | const newProduct = {...req.body, id: v4(), image}; 42 | products.push(newProduct); 43 | res.status(201).json({ 44 | status: "success", 45 | code: 201, 46 | data: { 47 | result: newProduct 48 | } 49 | }); 50 | } catch (error) { 51 | await fs.unlink(tempName); 52 | } 53 | 54 | }); 55 | 56 | app.get("/api/products", async(req, res)=> { 57 | res.json(products) 58 | }) 59 | 60 | app.listen(3000); 61 | 62 | 63 | -------------------------------------------------------------------------------- /lesson-9/multer-example/frontend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | 12 | 24 | 25 | -------------------------------------------------------------------------------- /lesson-9/multer-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /lesson-9/multer-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multer-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app", 9 | "start:dev": "nodemon app" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "nodemon": "^2.0.13" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "express": "^4.17.1", 20 | "multer": "^1.4.3", 21 | "uuid": "^8.3.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lesson-9/multer-example/public/products/2085-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-9/multer-example/public/products/2085-1.png -------------------------------------------------------------------------------- /lesson-9/multer-example/temp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-9/multer-example/temp/.gitkeep -------------------------------------------------------------------------------- /lesson-9/slides/multer-work-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/30-nodejs/670d182261478f59518e45914861b981376ea91a/lesson-9/slides/multer-work-schema.jpg --------------------------------------------------------------------------------