├── lesson-1 ├── .gitignore ├── README.md ├── index.html ├── node start │ └── index.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 │ ├── add-vanilla-js-library-problems.jpg │ ├── motivation-picture.png │ ├── npm-structure.jpg │ └── project-create-steps.jpg ├── lesson-10 ├── index.html ├── 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 │ ├── controllers │ └── products │ │ ├── getAll.js │ │ ├── getAll.test.js │ │ └── index.js │ ├── funcs │ ├── index.js │ ├── isLeapYear.js │ └── isLeapYear.test.js │ ├── index.html │ └── package.json ├── lesson-11 ├── auth-example │ ├── .env │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── controllers │ │ ├── auth │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── logout.js │ │ │ └── register.js │ │ ├── index.js │ │ ├── products │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getById.js │ │ │ ├── index.js │ │ │ ├── removeById.js │ │ │ ├── updateById.js │ │ │ └── updateStatus.js │ │ └── users │ │ │ ├── getCurrent.js │ │ │ ├── index.js │ │ │ └── verifyEmail.js │ ├── env.example │ ├── helpers │ │ ├── index.js │ │ └── sendEmail.js │ ├── middlewares │ │ ├── auth.js │ │ ├── ctrlWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ ├── product.js │ │ └── user.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ └── routes │ │ └── api │ │ ├── auth.js │ │ ├── products.js │ │ └── users.js ├── index.html ├── nodemailer │ ├── .gitignore │ ├── app.js │ └── package.json ├── sendgrid │ ├── .gitignore │ ├── app.js │ ├── helpers │ │ ├── index.js │ │ └── sendEmail.js │ └── package.json └── slides │ ├── mailing-schema.jpg │ ├── nodemailer.jpg │ └── sendgrid-schema.jpg ├── lesson-12 ├── README.md ├── index.html ├── 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-2 ├── README.md ├── commander-example │ ├── .gitignore │ ├── app.js │ ├── package.json │ └── products │ │ ├── add.js │ │ ├── filePath.js │ │ ├── getAll.js │ │ ├── getById.js │ │ ├── index.js │ │ ├── products.json │ │ ├── removeById.js │ │ ├── updateById.js │ │ └── updateProducts.js ├── index.html ├── process.argv-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── slides │ └── work-with-files-examples.jpg ├── work-with-files │ ├── .gitignore │ ├── app.js │ ├── files │ │ └── file.txt │ └── package.json ├── work-with-json-files │ ├── .gitignore │ ├── app.js │ ├── package.json │ └── products │ │ ├── add.js │ │ ├── filePath.js │ │ ├── getAll.js │ │ ├── getById.js │ │ ├── index.js │ │ ├── products.json │ │ ├── removeById.js │ │ ├── updateById.js │ │ └── updateProducts.js └── yargs-example │ ├── .gitignore │ ├── app.js │ ├── package.json │ └── products │ ├── add.js │ ├── filePath.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 │ └── views │ │ └── products.ejs ├── express-example-3 │ ├── .gitignore │ ├── app.js │ ├── index.html │ ├── package.json │ ├── products.js │ └── server.log ├── express-example-4 │ ├── .gitignore │ ├── app.js │ ├── data │ │ └── products.js │ ├── package.json │ └── routes │ │ └── api │ │ └── products.js ├── http-server-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── index.html └── slides │ ├── Client-Server-schema.jpg │ ├── REST-API │ ├── CRUD.jpg │ ├── HTTP-methods.jpg │ ├── REST-API-additional-rules.jpg │ ├── REST-API-basic-rules.jpg │ ├── Server-response-code.jpg │ └── old-routes-example.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 ├── index.html ├── nodejs-homework-template-master-2 │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── controllers │ │ ├── index.js │ │ └── products │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getById.js │ │ │ ├── index.js │ │ │ ├── removeById.js │ │ │ └── updateById.js │ ├── middlewares │ │ ├── ctrlWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── model │ │ └── products │ │ │ ├── add.js │ │ │ ├── filePath.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 │ │ ├── filePath.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 ├── lesson-5 ├── index.html ├── mongodb-project │ ├── .env.example │ ├── .gitignore │ ├── app.js │ ├── controllers │ │ ├── index.js │ │ └── products │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ └── index.js │ ├── middlewares │ │ ├── ctrlWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ └── product.js │ ├── package.json │ └── routes │ │ └── api │ │ └── products.js ├── process-env-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── products.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 └── nodejs-homework-template-master │ ├── .env │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ └── server.js │ ├── controllers │ ├── index.js │ └── products │ │ ├── add.js │ │ ├── getAll.js │ │ ├── getById.js │ │ ├── index.js │ │ ├── removeById.js │ │ ├── updateById.js │ │ └── updateStatus.js │ ├── env.example │ ├── middlewares │ ├── ctrlWrapper.js │ ├── index.js │ └── validation.js │ ├── models │ ├── index.js │ └── product.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ └── routes │ └── api │ └── products.js ├── lesson-7 ├── .gitignore ├── README.md ├── auth-example │ ├── .env │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── controllers │ │ ├── auth │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ └── register.js │ │ ├── index.js │ │ └── products │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getById.js │ │ │ ├── index.js │ │ │ ├── removeById.js │ │ │ ├── updateById.js │ │ │ └── updateStatus.js │ ├── env.example │ ├── middlewares │ │ ├── ctrlWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ ├── product.js │ │ └── user.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ └── routes │ │ └── api │ │ ├── auth.js │ │ └── products.js ├── hash-example │ ├── .gitignore │ ├── app.js │ └── package.json ├── index.html ├── jsonwebtoken-example │ ├── .gitignore │ ├── app.js │ └── package.json └── slides │ ├── HTTP-common-schema.jpg │ ├── HTTP-personal-request-schema.jpg │ ├── JWT-token-schema.jpg │ ├── frontend-backend-requests-with-token.jpg │ ├── hash-schema.jpg │ ├── jwt-token-real-life-example.jpg │ ├── logout-examples.jpg │ ├── process.env-and-deploy.jpg │ ├── register-auth-steps.jpg │ └── reigster-auth-create-steps.jpg ├── lesson-8 ├── auth-example │ ├── .env │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── app.js │ ├── bin │ │ └── server.js │ ├── controllers │ │ ├── auth │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── logout.js │ │ │ └── register.js │ │ ├── index.js │ │ ├── products │ │ │ ├── add.js │ │ │ ├── getAll.js │ │ │ ├── getById.js │ │ │ ├── index.js │ │ │ ├── removeById.js │ │ │ ├── updateById.js │ │ │ └── updateStatus.js │ │ └── users │ │ │ ├── getCurrent.js │ │ │ └── index.js │ ├── env.example │ ├── middlewares │ │ ├── auth.js │ │ ├── ctrlWrapper.js │ │ ├── index.js │ │ └── validation.js │ ├── models │ │ ├── index.js │ │ ├── product.js │ │ └── user.js │ ├── nodemon.json │ ├── package.json │ ├── readme.md │ └── routes │ │ └── api │ │ ├── auth.js │ │ ├── products.js │ │ └── users.js ├── index.html └── slides │ ├── HTTP-common-schema.jpg │ ├── HTTP-personal-request-schema.jpg │ ├── JWT-token-schema.jpg │ ├── frontend-backend-requests-with-token.jpg │ ├── hash-schema.jpg │ ├── jwt-token-real-life-example.jpg │ ├── logout-examples.jpg │ ├── process.env-and-deploy.jpg │ ├── register-auth-steps.jpg │ └── reigster-auth-create-steps.jpg └── lesson-9 ├── 2085-1.png ├── auth-example ├── .env ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── app.js ├── bin │ └── server.js ├── controllers │ ├── auth │ │ ├── index.js │ │ ├── login.js │ │ ├── logout.js │ │ └── register.js │ ├── index.js │ ├── products │ │ ├── add.js │ │ ├── getAll.js │ │ ├── getById.js │ │ ├── index.js │ │ ├── removeById.js │ │ ├── updateById.js │ │ └── updateStatus.js │ └── users │ │ ├── getCurrent.js │ │ ├── index.js │ │ └── updateAvatar.js ├── env.example ├── middlewares │ ├── auth.js │ ├── ctrlWrapper.js │ ├── index.js │ ├── upload.js │ └── validation.js ├── models │ ├── index.js │ ├── product.js │ └── user.js ├── nodemon.json ├── package.json ├── public │ └── avatars │ │ └── 61afac845d2f14829dd3b79a_2085-1.png ├── readme.md ├── routes │ └── api │ │ ├── auth.js │ │ ├── products.js │ │ └── users.js └── temp │ └── .gitkeep ├── multer-example ├── .gitignore ├── app.js ├── frontend.html ├── index.html ├── package.json ├── public │ └── products │ │ └── 2085-1.png └── temp │ └── .gitkeep └── slides └── multer-work-schema.jpg /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 | [Проблемы при добавлении библиотек на чистом JS](./slides/add-vanilla-js-library-problems.jpg) 12 | 13 | [Структура NPM](./slides/npm-structure.jpg) 14 | 15 | [Последовательность шагов при создании проекта](./slides/project-create-steps.jpg) 16 | -------------------------------------------------------------------------------- /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-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 | 10 | -------------------------------------------------------------------------------- /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 | // CommonJS 2 | // const nodemon = require("nodemon"); 3 | 4 | // const users = require("./users"); 5 | // console.log(users); 6 | 7 | // const {admins} = require("./users"); 8 | // console.log(admins); 9 | 10 | // const {getCurrentMonth} = require("./date"); 11 | const currentMonth = require("./date").getCurrentMonth(); 12 | // const currentMonth = getCurrentMonth(); 13 | console.log(`Сейчас ${currentMonth} месяц`); 14 | 15 | // const user = new require("./user"); 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /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 | 2 | import users from "./users.mjs"; 3 | console.log(users); 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-mjs/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.mjs", 9 | "start:dev": "nodemon index.mjs" 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 | const admins = ["Alex", "Andrey", "VAsiliy"]; 5 | 6 | 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 | console.log(users); 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lesson-1/node-module-es6-type/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-CommonJS-module", 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 | // 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 | export default users; 14 | -------------------------------------------------------------------------------- /lesson-1/npm-example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /lesson-1/npm-example/index.js: -------------------------------------------------------------------------------- 1 | console.log("Nodemon example") -------------------------------------------------------------------------------- /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 | "devDependencies": { 15 | "nodemon": "^2.0.14" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "express": "^4.17.1", 20 | "mongoose": "^6.0.12" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lesson-1/slides/JS-V8-setTimeout-work.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-1/slides/JS-V8-setTimeout-work.jpg -------------------------------------------------------------------------------- /lesson-1/slides/JS-V8-work.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-1/slides/JS-V8-work.jpg -------------------------------------------------------------------------------- /lesson-1/slides/Nodejs-structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-1/slides/Nodejs-structure.jpg -------------------------------------------------------------------------------- /lesson-1/slides/add-vanilla-js-library-problems.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-1/slides/add-vanilla-js-library-problems.jpg -------------------------------------------------------------------------------- /lesson-1/slides/motivation-picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-1/slides/motivation-picture.png -------------------------------------------------------------------------------- /lesson-1/slides/npm-structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-1/slides/npm-structure.jpg -------------------------------------------------------------------------------- /lesson-1/slides/project-create-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-1/slides/project-create-steps.jpg -------------------------------------------------------------------------------- /lesson-10/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /lesson-10/slides/QA-work.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/slides/QA-work.jpg -------------------------------------------------------------------------------- /lesson-10/slides/Test-driven-development-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/slides/Test-driven-development-ru.png -------------------------------------------------------------------------------- /lesson-10/slides/developing-with-test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/slides/developing-with-test.jpg -------------------------------------------------------------------------------- /lesson-10/slides/piramida.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/slides/piramida.drawio.png -------------------------------------------------------------------------------- /lesson-10/slides/test-first-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/slides/test-first-schema.jpg -------------------------------------------------------------------------------- /lesson-10/slides/test-instruments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/slides/test-instruments.png -------------------------------------------------------------------------------- /lesson-10/slides/test-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/slides/test-schema.jpg -------------------------------------------------------------------------------- /lesson-10/test-function-example/app.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/test-function-example/app.js -------------------------------------------------------------------------------- /lesson-10/test-function-example/controllers/products/getAll.js: -------------------------------------------------------------------------------- 1 | const products = [ 2 | { 3 | id: "1", 4 | name: "iPhone X", 5 | price: 17000 6 | } 7 | ]; 8 | 9 | const getAll = async(req, res)=> { 10 | res.json(products) 11 | } 12 | 13 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-10/test-function-example/controllers/products/getAll.test.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const request = require("supertest"); 3 | 4 | const getAll = require("./getAll"); 5 | 6 | const app = express(); 7 | 8 | app.get("/api/products", getAll); 9 | 10 | describe("test getAll controller", ()=> { 11 | let server; 12 | beforeAll(()=> server = app.listen(3000)); 13 | afterAll(()=> server.close()); 14 | 15 | test("getAll return products array", async()=> { 16 | const response = await request(app).get("/api/products"); 17 | expect(response.status).toBe(200); 18 | expect(Array.isArray(response.body)).toBe(true); 19 | const [product] = response.body; 20 | expect(typeof product.id).toBe("string"); 21 | expect(typeof product.name).toBe("string"); 22 | expect(typeof product.price).toBe("number"); 23 | }); 24 | }) -------------------------------------------------------------------------------- /lesson-10/test-function-example/controllers/products/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-10/test-function-example/controllers/products/index.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('Year must be exist'); 4 | } 5 | 6 | if(typeof year !== "number"){ 7 | throw new Error('Year must be number') 8 | } 9 | 10 | if(!Number.isInteger(year)){ 11 | throw new Error('Year must be integer'); 12 | } 13 | 14 | if(year < 42){ 15 | throw new Error('Year must me 42 or more'); 16 | } 17 | 18 | const date = new Date(year, 2, 0); 19 | const days = date.getDate(); 20 | return (days === 29); 21 | }; 22 | 23 | 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.4.3", 16 | "nodemon": "^2.0.13" 17 | }, 18 | "dependencies": { 19 | "express": "^4.17.1", 20 | "supertest": "^6.1.6" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lesson-11/auth-example/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.lhj89.mongodb.net/online_shop?retryWrites=true&w=majority 2 | SENDGRID_API_KEY=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 3 | SECRET_KEY=GHGSDFM23Tfgsfs3 4 | DB_USER=Bogdan 5 | DB_PASSWORD=pBje6ZbFRATcsTq 6 | DB_NAME=online_shop -------------------------------------------------------------------------------- /lesson-11/auth-example/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-11/auth-example/.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-11/auth-example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lesson-11/auth-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | require("dotenv").config(); 5 | 6 | const authRouter = require("./routes/api/auth"); 7 | const usersRouter = require("./routes/api/users"); 8 | const productsRouter = require("./routes/api/products"); 9 | 10 | const app = express() 11 | 12 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 13 | 14 | app.use(logger(formatsLogger)) 15 | app.use(cors()) 16 | app.use(express.json()) 17 | 18 | app.use("/api/auth", authRouter); 19 | app.use("/api/users", usersRouter); 20 | app.use('/api/products', productsRouter); 21 | 22 | app.use((req, res) => { 23 | res.status(404).json({ message: 'Not found' }) 24 | }) 25 | 26 | app.use((err, req, res, next) => { 27 | const {status = 500, message = "Server error"} = err; 28 | res.status(status).json({ message: err.message }) 29 | }) 30 | 31 | module.exports = app 32 | -------------------------------------------------------------------------------- /lesson-11/auth-example/bin/server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const app = require('../app'); 4 | 5 | const {DB_HOST, PORT = 3000} = process.env; 6 | 7 | mongoose.connect(DB_HOST) 8 | .then(()=> app.listen(PORT)) 9 | .catch(error => { 10 | console.log(error.message); 11 | process.exit(1); 12 | }) 13 | 14 | 15 | -------------------------------------------------------------------------------- /lesson-11/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-11/auth-example/controllers/auth/login.js: -------------------------------------------------------------------------------- 1 | const {Unauthorized} = require("http-errors"); 2 | const jwt = require("jsonwebtoken"); 3 | // const bcrypt = require("bcryptjs"); 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}); 12 | if(!user || !user.verify || !user.comparePassword(password)){ 13 | throw new Unauthorized("Email is wrong or not verify, or password is wrong"); 14 | } 15 | 16 | const payload = { 17 | id: user._id 18 | }; 19 | const token = jwt.sign(payload, SECRET_KEY, {expiresIn: "1h"}); 20 | await User.findByIdAndUpdate(user._id, {token}); 21 | res.json({ 22 | status: "success", 23 | code: 200, 24 | data: { 25 | token 26 | } 27 | }) 28 | } 29 | 30 | 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.status(204).json(); 7 | } 8 | 9 | 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 {sendEmail} = require("../../helpers"); 5 | const {User} = require("../../models"); 6 | 7 | const register = async(req, res)=> { 8 | const {name, email, password} = req.body; 9 | const user = await User.findOne({email}); 10 | if(user){ 11 | throw new Conflict(`User with ${email} already exist`) 12 | } 13 | const verificationToken = nanoid(); 14 | const newUser = new User({name, email, verificationToken}); 15 | 16 | newUser.setPassword(password); 17 | 18 | await newUser.save(); 19 | const mail = { 20 | to: email, 21 | subject: "Подтверждения email", 22 | html: `Подтвердить email` 23 | }; 24 | 25 | await sendEmail(mail); 26 | 27 | res.status(201).json({ 28 | status: "success", 29 | code: 201, 30 | data: { 31 | user: { 32 | email, 33 | name, 34 | verificationToken 35 | } 36 | } 37 | }); 38 | } 39 | 40 | module.exports = register; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | const auth = require("./auth"); 3 | const users = require("./users"); 4 | 5 | module.exports = { 6 | products, 7 | auth, 8 | users 9 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/products/add.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const add = async (req, res) => { 4 | const {_id} = req.user; 5 | const result = await Product.create({...req.body, owner: _id}); 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/products/getAll.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const getAll = async (req, res) => { 4 | const {_id} = req.user; 5 | const {page = 1, limit = 10} = req.query; 6 | const skip = (page - 1) * limit; 7 | const products = await Product.find({owner: _id}, "", {skip, limit: Number(limit)}).populate("owner", "_id name email"); 8 | 9 | res.json({ 10 | status: "success", 11 | code: 200, 12 | data: { 13 | result: products 14 | } 15 | }); 16 | }; 17 | 18 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/products/getById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const getById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findById(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/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 | const updateStatus = require("./updateStatus"); 7 | 8 | module.exports = { 9 | getAll, 10 | getById, 11 | add, 12 | updateById, 13 | updateStatus, 14 | removeById 15 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/products/removeById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const removeById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndRemove(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | message: "product deleted", 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/products/updateById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndUpdate(id, req.body, {new: true}); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/products/updateStatus.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateStatus = async (req, res) => { 6 | const { id } = req.params; 7 | const {status} = req.body; 8 | const result = await Product.findByIdAndUpdate(id, {status}, {new: true}); 9 | if (!result) { 10 | throw new NotFound(`Product with id=${id} not found`); 11 | } 12 | res.json({ 13 | status: "success", 14 | code: 200, 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = updateStatus; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/users/getCurrent.js: -------------------------------------------------------------------------------- 1 | const {User} = require("../../models"); 2 | 3 | const getCurrent = async(req, res)=> { 4 | const {name, email} = req.user; 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | user: { 10 | name, 11 | email 12 | } 13 | 14 | } 15 | }) 16 | } 17 | 18 | module.exports = getCurrent; -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/users/index.js: -------------------------------------------------------------------------------- 1 | const getCurrent = require("./getCurrent"); 2 | const verifyEmail = require("./verifyEmail"); 3 | 4 | module.exports = { 5 | getCurrent, 6 | verifyEmail 7 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/controllers/users/verifyEmail.js: -------------------------------------------------------------------------------- 1 | const {NotFound} = require("http-errors"); 2 | 3 | const {User} = require("../../models"); 4 | 5 | const verifyEmail = async(req, res)=> { 6 | const {verificationToken} = req.params; 7 | const user = await User.findOne({verificationToken}); 8 | if(!user){ 9 | throw NotFound(); 10 | } 11 | await User.findByIdAndUpdate(user._id, {verify: true, verificationToken: null}); 12 | 13 | res.json({ 14 | message: "Verify success" 15 | }) 16 | } 17 | 18 | module.exports = verifyEmail; -------------------------------------------------------------------------------- /lesson-11/auth-example/env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | DB_USER= 3 | DB_PASSWORD= 4 | DB_NAME= -------------------------------------------------------------------------------- /lesson-11/auth-example/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendEmail = require("./sendEmail"); 2 | 3 | module.exports = { 4 | sendEmail 5 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/helpers/sendEmail.js: -------------------------------------------------------------------------------- 1 | const sgMail = require("@sendgrid/mail"); 2 | require("dotenv").config(); 3 | 4 | const {SENDGRID_API_KEY} = process.env; 5 | 6 | sgMail.setApiKey(SENDGRID_API_KEY); 7 | 8 | const sendEmail = async(data)=> { 9 | const email = {...data, from: "bogdan.lyamzin.d@gmail.com"}; 10 | try { 11 | await sgMail.send(email); 12 | return true; 13 | } catch (error) { 14 | throw error; 15 | } 16 | } 17 | 18 | module.exports = sendEmail; 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson-11/auth-example/middlewares/ctrlWrapper.js: -------------------------------------------------------------------------------- 1 | const ctrlWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } catch (error) { 6 | next(error); 7 | } 8 | } 9 | } 10 | 11 | module.exports = ctrlWrapper; -------------------------------------------------------------------------------- /lesson-11/auth-example/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const ctrlWrapper = require("./ctrlWrapper"); 3 | const auth = require("./auth"); 4 | 5 | module.exports = { 6 | validation, 7 | ctrlWrapper, 8 | auth 9 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | error.status = 400; 6 | next(error); 7 | } 8 | next() 9 | } 10 | } 11 | 12 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-11/auth-example/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | const {User} = require("./user"); 3 | 4 | module.exports = { 5 | Product, 6 | User 7 | } -------------------------------------------------------------------------------- /lesson-11/auth-example/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-11/auth-example/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 | "bcryptjs": "^2.4.3", 13 | "cors": "2.8.5", 14 | "cross-env": "7.0.3", 15 | "dotenv": "^10.0.0", 16 | "express": "4.17.1", 17 | "http-errors": "^1.8.1", 18 | "joi": "^17.4.2", 19 | "jsonwebtoken": "^8.5.1", 20 | "mongoose": "^6.0.13", 21 | "morgan": "1.10.0", 22 | "nanoid": "^3.1.30", 23 | "uuid": "^8.3.2" 24 | }, 25 | "devDependencies": { 26 | "eslint": "^7.19.0", 27 | "eslint-config-standard": "^16.0.2", 28 | "eslint-plugin-import": "^2.22.1", 29 | "eslint-plugin-node": "^11.1.0", 30 | "eslint-plugin-promise": "^4.2.1", 31 | "nodemon": "2.0.7" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lesson-11/auth-example/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-11/auth-example/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, validation, ctrlWrapper} = require("../../middlewares"); 4 | const {auth: ctrl} = require("../../controllers"); 5 | const {joiRegisterSchema, joiLoginSchema} = require("../../models/user"); 6 | 7 | const router = express.Router(); 8 | 9 | router.post("/register", validation(joiRegisterSchema), ctrlWrapper(ctrl.register)); 10 | // router.post("/signup") 11 | router.post("/login", validation(joiLoginSchema), ctrlWrapper(ctrl.login)); 12 | // router.post("/signin") 13 | router.get("/logout", auth, ctrlWrapper(ctrl.logout)); 14 | // router.get("/signout") 15 | module.exports = router; -------------------------------------------------------------------------------- /lesson-11/auth-example/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, validation, ctrlWrapper} = require("../../middlewares"); 4 | const {joiSchema, statusJoiSchema} = require("../../models/product"); 5 | const {products: ctrl} = require("../../controllers") 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", auth, ctrlWrapper(ctrl.getAll)); 10 | 11 | router.get("/:id", ctrlWrapper(ctrl.getById)); 12 | 13 | router.post("/", auth, validation(joiSchema), ctrlWrapper(ctrl.add)); 14 | 15 | router.put("/:id", validation(joiSchema), ctrlWrapper(ctrl.updateById)); 16 | 17 | router.patch("/:id/status", validation(statusJoiSchema), ctrlWrapper(ctrl.updateStatus)); 18 | 19 | router.delete("/:id", ctrlWrapper(ctrl.removeById)); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /lesson-11/auth-example/routes/api/users.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, ctrlWrapper} = require("../../middlewares"); 4 | const {users: ctrl} = require("../../controllers"); 5 | 6 | const router = express.Router(); 7 | 8 | router.get("/current", auth, ctrlWrapper(ctrl.getCurrent)); 9 | 10 | router.get("/verify/:verificationToken", ctrlWrapper(ctrl.verifyEmail)); 11 | 12 | module.exports = router; -------------------------------------------------------------------------------- /lesson-11/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /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 {META_PASSWORD} = process.env; 5 | 6 | const nodemailerConfig = { 7 | host: "smtp.meta.ua", 8 | port: 465, // 25, 465 и 2255 9 | secure: true, 10 | auth: { 11 | user: "bogdan.lyamzin.d@meta.ua", 12 | pass: META_PASSWORD 13 | } 14 | }; 15 | 16 | const transporter = nodemailer.createTransport(nodemailerConfig); 17 | 18 | const email = { 19 | to: "hiyowop403@kingsready.com", 20 | from: "bogdan.lyamzin.d@meta.ua", 21 | subject: "Новая заявка с сайта", 22 | html: "

С сайта пришла новая заявка

" 23 | }; 24 | 25 | transporter.sendMail(email) 26 | .then(()=> console.log("Email send success")) 27 | .catch(error => console.log(error.message)) -------------------------------------------------------------------------------- /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.7.2" 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_API_KEY} = process.env; 5 | 6 | sgMail.setApiKey(SENDGRID_API_KEY); 7 | 8 | const email = { 9 | to: "hiyowop403@kingsready.com", 10 | from: "bogdan.lyamzin.d@gmail.com", 11 | subject: "Новая заявка с сайта", 12 | html: "

С сайта пришла новая заявка

" 13 | }; 14 | 15 | sgMail.send(email) 16 | .then(()=> console.log("Email send success")) 17 | .catch(error => console.log(error.message)) 18 | -------------------------------------------------------------------------------- /lesson-11/sendgrid/helpers/index.js: -------------------------------------------------------------------------------- 1 | const sendEmail = require("./sendEmail"); 2 | 3 | module.exports = { 4 | sendEmail 5 | } -------------------------------------------------------------------------------- /lesson-11/sendgrid/helpers/sendEmail.js: -------------------------------------------------------------------------------- 1 | const sgMail = require("@sendgrid/mail"); 2 | require("dotenv").config(); 3 | 4 | const {SENDGRID_API_KEY} = process.env; 5 | 6 | sgMail.setApiKey(SENDGRID_API_KEY); 7 | 8 | const sendEmail = async(data)=> { 9 | const email = {...data, from: "bogdan.lyamzin.d@gmail.com"}; 10 | try { 11 | await sgMail.send(email); 12 | return true; 13 | } catch (error) { 14 | throw error; 15 | } 16 | } 17 | 18 | module.exports = sendEmail; 19 | 20 | 21 | -------------------------------------------------------------------------------- /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.6.0", 19 | "dotenv": "^10.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lesson-11/slides/mailing-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-11/slides/mailing-schema.jpg -------------------------------------------------------------------------------- /lesson-11/slides/nodemailer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-11/slides/nodemailer.jpg -------------------------------------------------------------------------------- /lesson-11/slides/sendgrid-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/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/slides/different-between-websockets-and-http.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-12/slides/different-between-websockets-and-http.jpg -------------------------------------------------------------------------------- /lesson-12/slides/web-socket-client-server-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-12/slides/web-socket-client-server-schema.jpg -------------------------------------------------------------------------------- /lesson-12/slides/web-socket-personal-client-object.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-12/slides/web-socket-personal-client-object.jpg -------------------------------------------------------------------------------- /lesson-12/slides/websocket-main-features.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-12/slides/websocket-main-features.jpg -------------------------------------------------------------------------------- /lesson-12/slides/websocket-projects.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/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", (data)=> { 11 | const message = JSON.parse(data); 12 | users.forEach(user => { 13 | if(user !== newUser){ 14 | user.send(JSON.stringify(message)); 15 | } 16 | }) 17 | }) 18 | }) -------------------------------------------------------------------------------- /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": "^8.3.0" 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 | // console.log("Новое подключение с фронтенда") 10 | // setTimeout(()=> { 11 | // newClient.send("Добро пожаловать на наш сервер!") 12 | // }, 3000) 13 | clients.forEach(client => { 14 | if(client !== newClient){ 15 | client.send("К нам присоединился новый пользователь") 16 | } 17 | }) 18 | }) 19 | 20 | 21 | -------------------------------------------------------------------------------- /lesson-12/websocket-basic-example/frontend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 22 | 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": "^8.3.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-2/README.md: -------------------------------------------------------------------------------- 1 | [Где используется работа с файлами в Node.js](./slides/work-with-files-examples.png) 2 | -------------------------------------------------------------------------------- /lesson-2/commander-example/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | yarn.lock 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-2/commander-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commander-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "nodemon": "^2.0.12" 14 | }, 15 | "dependencies": { 16 | "commander": "^8.2.0", 17 | "uuid": "^8.3.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lesson-2/commander-example/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 | await updateProducts(products); 11 | return newProduct; 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-2/commander-example/products/filePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const filePath = path.join(__dirname, "products.json"); 4 | 5 | module.exports = filePath; -------------------------------------------------------------------------------- /lesson-2/commander-example/products/getAll.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const getAll = async()=> { 6 | const data = await fs.readFile(filePath); 7 | const products = JSON.parse(data); 8 | return products; 9 | } 10 | 11 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-2/commander-example/products/getById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | 3 | const getById = async(id)=> { 4 | const products = await getAll(); 5 | const result = products.find(item => item.id === id); 6 | if(!result){ 7 | return null; 8 | } 9 | return result; 10 | } 11 | 12 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-2/commander-example/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 | } -------------------------------------------------------------------------------- /lesson-2/commander-example/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": 5, 36 | "location": "Home baking" 37 | } 38 | ] -------------------------------------------------------------------------------- /lesson-2/commander-example/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 [removeProduct] = products.splice(idx, 1); 11 | // await updateProducts(products); 12 | // return removeProduct 13 | const newProducts = products.filter((_, index) => index !== idx); 14 | await updateProducts(newProducts); 15 | return products[idx]; 16 | } 17 | 18 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-2/commander-example/products/updateById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 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 | products[idx] = {...data, id}; 11 | await updateProducts(products); 12 | return products[idx]; 13 | } 14 | 15 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-2/commander-example/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const updateProducts = async(products)=> { 6 | await fs.writeFile(filePath, JSON.stringify(products)); 7 | } 8 | 9 | module.exports = updateProducts; -------------------------------------------------------------------------------- /lesson-2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 15 | 16 | 21 | 22 | -------------------------------------------------------------------------------- /lesson-2/process.argv-example/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | yarn.lock 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-2/process.argv-example/app.js: -------------------------------------------------------------------------------- 1 | const actionIndex = process.argv.indexOf("--action"); 2 | 3 | if(actionIndex !== -1){ 4 | 5 | } -------------------------------------------------------------------------------- /lesson-2/process.argv-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "process.argv-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "nodemon": "^2.0.12" 14 | }, 15 | "dependencies": { 16 | "uuid": "^8.3.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lesson-2/slides/work-with-files-examples.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/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 | // const fs = require("fs").promises; 3 | 4 | const fileOperation = async(filePath, action = "read", data = "") => { 5 | switch(action){ 6 | case "read": 7 | const text = await fs.readFile(filePath, "utf-8"); 8 | console.log(text); 9 | break; 10 | case "add": 11 | await fs.appendFile(filePath, data); 12 | break; 13 | case "replace": 14 | await fs.writeFile(filePath, data); 15 | break; 16 | default: 17 | console.log("Unknown action") 18 | } 19 | } 20 | 21 | // fileOperation("files/file.txt"); 22 | // fileOperation("files/file.txt", "add", "\nНе плюйся - никто не носит золота во рту"); 23 | fileOperation("files/file.txt", "replace", "Не плюйся - никто не носит золота во рту"); 24 | 25 | // fs.readFile("files/file.txt", "utf-8") 26 | // .then(data => { 27 | // console.log(data); 28 | // // const text = data.toString(); 29 | // // console.log(text); 30 | // }) 31 | // .catch(error => console.log(error.message)) 32 | 33 | -------------------------------------------------------------------------------- /lesson-2/work-with-files/files/file.txt: -------------------------------------------------------------------------------- 1 | 2 | Не плюйся - никто не носит золота во рту -------------------------------------------------------------------------------- /lesson-2/work-with-files/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "work-with-files", 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 | } 18 | -------------------------------------------------------------------------------- /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": "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 | "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 | await updateProducts(products); 11 | return newProduct; 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/filePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const filePath = path.join(__dirname, "products.json"); 4 | 5 | module.exports = filePath; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/getAll.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const getAll = async()=> { 6 | const data = await fs.readFile(filePath); 7 | const products = JSON.parse(data); 8 | return products; 9 | } 10 | 11 | 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 result = products.find(item => item.id === id); 6 | if(!result){ 7 | return null; 8 | } 9 | return result; 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 | } -------------------------------------------------------------------------------- /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": 5, 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 [removeProduct] = products.splice(idx, 1); 11 | // await updateProducts(products); 12 | // return removeProduct 13 | const newProducts = products.filter((_, index) => index !== idx); 14 | await updateProducts(newProducts); 15 | return products[idx]; 16 | } 17 | 18 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/updateById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 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 | products[idx] = {...data, id}; 11 | await updateProducts(products); 12 | return products[idx]; 13 | } 14 | 15 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-2/work-with-json-files/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const updateProducts = async(products)=> { 6 | await fs.writeFile(filePath, JSON.stringify(products)); 7 | } 8 | 9 | module.exports = updateProducts; -------------------------------------------------------------------------------- /lesson-2/yargs-example/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | yarn.lock 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-2/yargs-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yargs-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "nodemon": "^2.0.12" 14 | }, 15 | "dependencies": { 16 | "uuid": "^8.3.2", 17 | "yargs": "^17.1.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lesson-2/yargs-example/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 | await updateProducts(products); 11 | return newProduct; 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-2/yargs-example/products/filePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const filePath = path.join(__dirname, "products.json"); 4 | 5 | module.exports = filePath; -------------------------------------------------------------------------------- /lesson-2/yargs-example/products/getAll.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const getAll = async()=> { 6 | const data = await fs.readFile(filePath); 7 | const products = JSON.parse(data); 8 | return products; 9 | } 10 | 11 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-2/yargs-example/products/getById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | 3 | const getById = async(id)=> { 4 | const products = await getAll(); 5 | const result = products.find(item => item.id === id); 6 | if(!result){ 7 | return null; 8 | } 9 | return result; 10 | } 11 | 12 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-2/yargs-example/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 | } -------------------------------------------------------------------------------- /lesson-2/yargs-example/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": 5, 36 | "location": "Home baking" 37 | } 38 | ] -------------------------------------------------------------------------------- /lesson-2/yargs-example/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 [removeProduct] = products.splice(idx, 1); 11 | // await updateProducts(products); 12 | // return removeProduct 13 | const newProducts = products.filter((_, index) => index !== idx); 14 | await updateProducts(newProducts); 15 | return products[idx]; 16 | } 17 | 18 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-2/yargs-example/products/updateById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 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 | products[idx] = {...data, id}; 11 | await updateProducts(products); 12 | return products[idx]; 13 | } 14 | 15 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-2/yargs-example/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const updateProducts = async(products)=> { 6 | await fs.writeFile(filePath, JSON.stringify(products)); 7 | } 8 | 9 | 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 | // Если прийдет GET запрос на адрес /contacts, выполнить эту функцию 6 | app.get("/contacts", (request, response)=> { 7 | // console.log(request.url); 8 | // console.log(request.method); 9 | // console.log(request.headers); 10 | response.send("

Contacts page

") 11 | }); 12 | 13 | app.get("/contact", (request, response)=> { 14 | response.send("

Contact page

") 15 | }) 16 | 17 | app.get("/", (request, response)=> { 18 | response.send("

Home page

") 19 | }) 20 | 21 | app.listen(3000, ()=> console.log("Server running")); -------------------------------------------------------------------------------- /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("json spaces", 18); 8 | 9 | app.get("/products", (req, res)=> { 10 | // res.json(null); 11 | // res.send(null); 12 | // res.json({ 13 | // status: "success", 14 | // code: 200, 15 | // data: { 16 | // result: products 17 | // } 18 | // }); 19 | // res.json(products); 20 | // res.send(products); 21 | // res.render("products", {name: "iPhone"} ) 22 | }); 23 | 24 | app.listen(3000); 25 | 26 | -------------------------------------------------------------------------------- /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-2/views/products.ejs: -------------------------------------------------------------------------------- 1 |

<% name %>

-------------------------------------------------------------------------------- /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 | // app.use(async(req, res, next)=> { 13 | // const {method, url} = req; 14 | // const date = moment().format("DD-MM-YYYY_hh:mm:ss"); 15 | // await fs.appendFile("server.log", `\n${method} ${url} ${date}`); 16 | // next(); 17 | // }) 18 | 19 | // app.use((req, res, next)=> { 20 | // console.log("First middleware"); 21 | // next(); 22 | // }); 23 | 24 | // app.use((req, res, next)=> { 25 | // console.log("Second middleware"); 26 | // next(); 27 | // }) 28 | 29 | app.get("/products", (req, res)=> { 30 | res.json(products); 31 | }) 32 | 33 | 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 | GET /products 21.09.2021_20:32:55 2 | 3 | GET /products 15-11-2021_08:24:23 4 | GET /orders 15-11-2021_08:24:37 -------------------------------------------------------------------------------- /lesson-3/express-example-4/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | package-lock.json 4 | yarn.lock 5 | .env 6 | node_modules/ -------------------------------------------------------------------------------- /lesson-3/express-example-4/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | 4 | const productsRouter = require("./routes/api/products"); 5 | 6 | const app = express(); 7 | 8 | app.use(cors()); 9 | app.use(express.json()); 10 | 11 | app.use("/api/products", productsRouter); 12 | 13 | app.listen(3000); -------------------------------------------------------------------------------- /lesson-3/express-example-4/data/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-4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example-4", 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 | "uuid": "^8.3.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lesson-3/express-example-4/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const {v4} = require("uuid"); 3 | 4 | const products = require("../../data/products"); 5 | 6 | const router = express.Router(); 7 | /* 8 | 1. Получить все товары. 9 | 2. Получить один товар по id. 10 | 3. Добавить товар. 11 | 4. Обновить товар по id. 12 | 5. Удалить товар по id. 13 | */ 14 | // GET /api/products 15 | router.get("/", (req, res)=> { 16 | res.json({ 17 | status: "success", 18 | code: 200, 19 | data: { 20 | result: products 21 | } 22 | }) 23 | }); 24 | 25 | router.get("/:id", (req, res)=> { 26 | const {id} = req.params; 27 | const result = products.find(item => item._id === id); 28 | if(!result){ 29 | res.status(404).json({ 30 | status: "error", 31 | code: 404, 32 | message: `Product with id=${id} not found` 33 | }) 34 | } 35 | res.json({ 36 | status: "success", 37 | code: 200, 38 | data: { 39 | result 40 | } 41 | }) 42 | }) 43 | // POST /api/products 44 | router.post("/", (req, res)=> { 45 | const newProduct = {...req.body, id: v4()}; 46 | products.push(newProduct); 47 | res.status(201).json({ 48 | status: "success", 49 | code: 201, 50 | data: { 51 | result: newProduct 52 | } 53 | }); 54 | }); 55 | 56 | 57 | module.exports = router; -------------------------------------------------------------------------------- /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 | 16 | 17 | -------------------------------------------------------------------------------- /lesson-3/slides/Client-Server-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/Client-Server-schema.jpg -------------------------------------------------------------------------------- /lesson-3/slides/REST-API/CRUD.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/REST-API/CRUD.jpg -------------------------------------------------------------------------------- /lesson-3/slides/REST-API/HTTP-methods.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/REST-API/HTTP-methods.jpg -------------------------------------------------------------------------------- /lesson-3/slides/REST-API/REST-API-additional-rules.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/REST-API/REST-API-additional-rules.jpg -------------------------------------------------------------------------------- /lesson-3/slides/REST-API/REST-API-basic-rules.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/REST-API/REST-API-basic-rules.jpg -------------------------------------------------------------------------------- /lesson-3/slides/REST-API/Server-response-code.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/REST-API/Server-response-code.jpg -------------------------------------------------------------------------------- /lesson-3/slides/REST-API/old-routes-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/REST-API/old-routes-example.jpg -------------------------------------------------------------------------------- /lesson-3/slides/fullstack-developer-cors-problem-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/fullstack-developer-cors-problem-2.jpg -------------------------------------------------------------------------------- /lesson-3/slides/fullstack-developer-cors-problem.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/fullstack-developer-cors-problem.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema-details-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/middleware-work-schema-details-2.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema-details-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/middleware-work-schema-details-3.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema-details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/middleware-work-schema-details.jpg -------------------------------------------------------------------------------- /lesson-3/slides/middleware-work-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/middleware-work-schema.jpg -------------------------------------------------------------------------------- /lesson-3/slides/what-is-it-cors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-3/slides/what-is-it-cors.jpg -------------------------------------------------------------------------------- /lesson-4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 16 | 17 | -------------------------------------------------------------------------------- /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 | app.use((req, res) => { 18 | res.status(404).json({ message: 'Not found' }) 19 | }) 20 | 21 | app.use((err, req, res, next) => { 22 | const {status = 500, message = "Server error"} = err; 23 | res.status(status).json({ message: err.message }) 24 | }) 25 | 26 | module.exports = app 27 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/bin/server.js: -------------------------------------------------------------------------------- 1 | const app = require('../app') 2 | 3 | const {PORT = 3000} = process.env; 4 | 5 | app.listen(PORT, () => { 6 | console.log(`Server running. Use our API on port: ${PORT}`) 7 | }) 8 | -------------------------------------------------------------------------------- /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/add.js: -------------------------------------------------------------------------------- 1 | const productsOperations = require("../../model/products"); 2 | 3 | const add = async (req, res) => { 4 | const result = await productsOperations.add(req.body); 5 | res.status(201).json({ 6 | status: "success", 7 | code: 201, 8 | data: { 9 | result 10 | } 11 | }) 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/controllers/products/getAll.js: -------------------------------------------------------------------------------- 1 | const productsOperations = require("../../model/products"); 2 | 3 | const getAll = async (req, res) => { 4 | const products = await productsOperations.getAll(); 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | result: products 10 | } 11 | }); 12 | }; 13 | 14 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/controllers/products/getById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const productsOperations = require("../../model/products"); 4 | 5 | const getById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await productsOperations.getById(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/controllers/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 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/controllers/products/removeById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const productsOperations = require("../../model/products"); 4 | 5 | const removeById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await productsOperations.removeById(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | message: "product deleted", 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/controllers/products/updateById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const productsOperations = require("../../model/products") 4 | 5 | const updateById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await productsOperations.updateById(id, req.body); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/middlewares/ctrlWrapper.js: -------------------------------------------------------------------------------- 1 | const ctrlWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } catch (error) { 6 | next(error); 7 | } 8 | } 9 | } 10 | 11 | module.exports = ctrlWrapper; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const ctrlWrapper = require("./ctrlWrapper"); 3 | 4 | module.exports = { 5 | validation, 6 | ctrlWrapper 7 | } -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | error.status = 400; 6 | next(error); 7 | } 8 | next() 9 | } 10 | } 11 | 12 | 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 | await updateProducts(products); 11 | return newProduct; 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/filePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const filePath = path.join(__dirname, "products.json"); 4 | 5 | module.exports = filePath; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/getAll.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const getAll = async()=> { 6 | const data = await fs.readFile(filePath); 7 | const products = JSON.parse(data); 8 | return products; 9 | } 10 | 11 | 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 result = products.find(item => item.id === id); 6 | if(!result){ 7 | return null; 8 | } 9 | return result; 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 | } -------------------------------------------------------------------------------- /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"}] -------------------------------------------------------------------------------- /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 [removeProduct] = products.splice(idx, 1); 11 | // await updateProducts(products); 12 | // return removeProduct 13 | const newProducts = products.filter((_, index) => index !== idx); 14 | await updateProducts(newProducts); 15 | return products[idx]; 16 | } 17 | 18 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/updateById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 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 | products[idx] = {...data, id}; 11 | await updateProducts(products); 12 | return products[idx]; 13 | } 14 | 15 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master-2/model/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const updateProducts = async(products)=> { 6 | await fs.writeFile(filePath, JSON.stringify(products)); 7 | } 8 | 9 | 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", 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.1", 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/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {validation, ctrlWrapper} = require("../../middlewares"); 4 | const {productSchema} = require("../../schemas"); 5 | const {products: ctrl} = require("../../controllers") 6 | 7 | const validateMiddleware = validation(productSchema); 8 | /* 9 | validateMiddleware = (req, res, next)=> { 10 | const {error} = productSchema.validate(req.body); 11 | if(error){ 12 | error.status = 400; 13 | next(error); 14 | } 15 | next() 16 | } 17 | */ 18 | const router = express.Router(); 19 | 20 | router.get("/", ctrlWrapper(ctrl.getAll)); 21 | 22 | router.get("/:id", ctrlWrapper(ctrl.getById)); 23 | 24 | router.post("/", validateMiddleware, ctrlWrapper(ctrl.add)); 25 | 26 | router.put("/:id", validation(productSchema), ctrlWrapper(ctrl.updateById)); 27 | 28 | router.delete("/:id", ctrlWrapper(ctrl.removeById)) 29 | 30 | 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().required(), 5 | price: Joi.number().min(0.01).required(), 6 | location: Joi.string().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 | app.use((req, res) => { 18 | res.status(404).json({ message: 'Not found' }) 19 | }) 20 | 21 | app.use((err, req, res, next) => { 22 | const {status = 500, message = "Server error"} = err; 23 | res.status(status).json({ message: err.message }) 24 | }) 25 | 26 | module.exports = app 27 | -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/bin/server.js: -------------------------------------------------------------------------------- 1 | const app = require('../app') 2 | 3 | const {PORT = 3000} = process.env; 4 | 5 | app.listen(PORT, () => { 6 | console.log(`Server running. Use our API on port: ${PORT}`) 7 | }) 8 | -------------------------------------------------------------------------------- /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 | await updateProducts(products); 11 | return newProduct; 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/filePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const filePath = path.join(__dirname, "products.json"); 4 | 5 | module.exports = filePath; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/getAll.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const getAll = async()=> { 6 | const data = await fs.readFile(filePath); 7 | const products = JSON.parse(data); 8 | return products; 9 | } 10 | 11 | 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 result = products.find(item => item.id === id); 6 | if(!result){ 7 | return null; 8 | } 9 | return result; 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 | } -------------------------------------------------------------------------------- /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"}] -------------------------------------------------------------------------------- /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 [removeProduct] = products.splice(idx, 1); 11 | // await updateProducts(products); 12 | // return removeProduct 13 | const newProducts = products.filter((_, index) => index !== idx); 14 | await updateProducts(newProducts); 15 | return products[idx]; 16 | } 17 | 18 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/updateById.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const updateProducts = require("./updateProducts"); 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 | products[idx] = {...data, id}; 11 | await updateProducts(products); 12 | return products[idx]; 13 | } 14 | 15 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-4/nodejs-homework-template-master/model/products/updateProducts.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const filePath = require("./filePath"); 4 | 5 | const updateProducts = async(products)=> { 6 | await fs.writeFile(filePath, JSON.stringify(products)); 7 | } 8 | 9 | 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 | "http-errors": "^1.8.1", 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-5/mongodb-project/.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | dB_USER= 3 | DB_PASSWORD= 4 | DB_NAME= -------------------------------------------------------------------------------- /lesson-5/mongodb-project/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | config.js 3 | package-lock.json 4 | yarn.lock 5 | yarn.log 6 | yarn.error 7 | node_modules/ -------------------------------------------------------------------------------- /lesson-5/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 | const {DB_HOST, PORT = 3000} = process.env; 16 | 17 | mongoose.connect(DB_HOST) 18 | .then(()=> app.listen(PORT)) 19 | .catch(error => { 20 | console.log(error.message); 21 | process.exit(1); 22 | }) -------------------------------------------------------------------------------- /lesson-5/mongodb-project/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | 3 | module.exports = { 4 | products 5 | } -------------------------------------------------------------------------------- /lesson-5/mongodb-project/controllers/products/add.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const add = async(req, res)=> { 4 | const result = await Product.create(req.body); 5 | res.status(201).json({ 6 | status: "success", 7 | code: 201, 8 | data: { 9 | result 10 | } 11 | }) 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-5/mongodb-project/controllers/products/getAll.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const getAll = async(req, res)=> { 4 | const result = await Product.find({}); 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | result 10 | } 11 | }) 12 | } 13 | 14 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-5/mongodb-project/controllers/products/index.js: -------------------------------------------------------------------------------- 1 | const getAll = require("./getAll"); 2 | const add = require("./add"); 3 | 4 | module.exports = { 5 | getAll, 6 | add 7 | } 8 | -------------------------------------------------------------------------------- /lesson-5/mongodb-project/middlewares/ctrlWrapper.js: -------------------------------------------------------------------------------- 1 | const ctrlWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } catch (error) { 6 | next(error); 7 | } 8 | } 9 | } 10 | 11 | module.exports = ctrlWrapper; -------------------------------------------------------------------------------- /lesson-5/mongodb-project/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const ctrlWrapper = require("./ctrlWrapper"); 3 | 4 | module.exports = { 5 | validation, 6 | ctrlWrapper 7 | } -------------------------------------------------------------------------------- /lesson-5/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 | error.status = 400; 6 | next(error); 7 | } 8 | next() 9 | } 10 | } 11 | 12 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-5/mongodb-project/models/index.js: -------------------------------------------------------------------------------- 1 | const Product = require("./product"); 2 | 3 | module.exports = { 4 | Product 5 | } -------------------------------------------------------------------------------- /lesson-5/mongodb-project/models/product.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | 3 | const productSchema = Schema({ 4 | name: String, 5 | price: Number, 6 | location: String 7 | }); 8 | 9 | const Product = model("product", productSchema); 10 | // categories => category 11 | // mice => mouse 12 | 13 | module.exports = Product; -------------------------------------------------------------------------------- /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.13" 16 | }, 17 | "dependencies": { 18 | "cors": "^2.8.5", 19 | "dotenv": "^10.0.0", 20 | "express": "^4.17.1", 21 | "mongoose": "^6.0.13" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lesson-5/mongodb-project/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {ctrlWrapper} = require("../../middlewares"); 4 | const {products: ctrl} = require("../../controllers"); 5 | 6 | const router = express.Router(); 7 | 8 | router.get("/", ctrlWrapper(ctrl.getAll)); 9 | 10 | router.post("/", ctrlWrapper(ctrl.add)) 11 | 12 | module.exports = router; -------------------------------------------------------------------------------- /lesson-5/process-env-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules/ -------------------------------------------------------------------------------- /lesson-5/process-env-example/app.js: -------------------------------------------------------------------------------- 1 | console.log(process.env.DB_HOST); -------------------------------------------------------------------------------- /lesson-5/process-env-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "process-env-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 | } 18 | -------------------------------------------------------------------------------- /lesson-5/products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "cheese", 4 | "price": 2.5, 5 | "location": "Refrigerated foods" 6 | }, 7 | { 8 | "name": "Crisps", 9 | "price": 4, 10 | "location": "the Snack isle" 11 | }, 12 | { 13 | "name": "Pizza", 14 | "price": 4, 15 | "location": "Refrigerated foods" 16 | }, 17 | { 18 | "name": "Chocolate", 19 | "price": 1.5, 20 | "location": "the Snack isle" 21 | }, 22 | { 23 | "name": "Self-raising flour", 24 | "price": 1.5, 25 | "location": "Home baking" 26 | }, 27 | { 28 | "name": "Ground almonds", 29 | "price": 5, 30 | "location": "Home baking" 31 | } 32 | ] -------------------------------------------------------------------------------- /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/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/backend-structure.jpg -------------------------------------------------------------------------------- /lesson-5/slides/database-types.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/database-types.jpg -------------------------------------------------------------------------------- /lesson-5/slides/documents-database-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/documents-database-schema.jpg -------------------------------------------------------------------------------- /lesson-5/slides/dotenv-work-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/dotenv-work-schema.jpg -------------------------------------------------------------------------------- /lesson-5/slides/mongodb-database-structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/mongodb-database-structure.jpg -------------------------------------------------------------------------------- /lesson-5/slides/remote-database.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/remote-database.jpg -------------------------------------------------------------------------------- /lesson-5/slides/schema-model-collection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/schema-model-collection.jpg -------------------------------------------------------------------------------- /lesson-5/slides/schema-model-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-5/slides/schema-model-example.jpg -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.lhj89.mongodb.net/online_shop?retryWrites=true&w=majority 2 | DB_USER=Bogdan 3 | DB_PASSWORD=pBje6ZbFRATcsTq 4 | DB_NAME=online_shop -------------------------------------------------------------------------------- /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 | require("dotenv").config(); 5 | 6 | const productsRouter = require("./routes/api/products"); 7 | 8 | const app = express() 9 | 10 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 11 | 12 | app.use(logger(formatsLogger)) 13 | app.use(cors()) 14 | app.use(express.json()) 15 | 16 | app.use('/api/products', productsRouter) 17 | 18 | app.use((req, res) => { 19 | res.status(404).json({ message: 'Not found' }) 20 | }) 21 | 22 | app.use((err, req, res, next) => { 23 | const {status = 500, message = "Server error"} = err; 24 | res.status(status).json({ message: err.message }) 25 | }) 26 | 27 | module.exports = app 28 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/bin/server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const app = require('../app'); 4 | 5 | const {DB_HOST, PORT = 3000} = process.env; 6 | 7 | mongoose.connect(DB_HOST) 8 | .then(()=> app.listen(PORT)) 9 | .catch(error => { 10 | console.log(error.message); 11 | process.exit(1); 12 | }) 13 | 14 | 15 | -------------------------------------------------------------------------------- /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/controllers/products/add.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const add = async (req, res) => { 4 | const result = await Product.create(req.body); 5 | res.status(201).json({ 6 | status: "success", 7 | code: 201, 8 | data: { 9 | result 10 | } 11 | }) 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/controllers/products/getAll.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const getAll = async (req, res) => { 4 | const products = await Product.find({}); 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | result: products 10 | } 11 | }); 12 | }; 13 | 14 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/controllers/products/getById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const getById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findById(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/controllers/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 | const updateStatus = require("./updateStatus"); 7 | 8 | module.exports = { 9 | getAll, 10 | getById, 11 | add, 12 | updateById, 13 | updateStatus, 14 | removeById 15 | } -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/controllers/products/removeById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const removeById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndRemove(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | message: "product deleted", 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/controllers/products/updateById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndUpdate(id, req.body, {new: true}); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/controllers/products/updateStatus.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateStatus = async (req, res) => { 6 | const { id } = req.params; 7 | const {status} = req.body; 8 | const result = await Product.findByIdAndUpdate(id, {status}, {new: true}); 9 | if (!result) { 10 | throw new NotFound(`Product with id=${id} not found`); 11 | } 12 | res.json({ 13 | status: "success", 14 | code: 200, 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = updateStatus; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | DB_USER= 3 | DB_PASSWORD= 4 | DB_NAME= -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/middlewares/ctrlWrapper.js: -------------------------------------------------------------------------------- 1 | const ctrlWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } catch (error) { 6 | next(error); 7 | } 8 | } 9 | } 10 | 11 | module.exports = ctrlWrapper; -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const ctrlWrapper = require("./ctrlWrapper"); 3 | 4 | module.exports = { 5 | validation, 6 | ctrlWrapper 7 | } -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | error.status = 400; 6 | next(error); 7 | } 8 | next() 9 | } 10 | } 11 | 12 | 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}$/; 5 | 6 | const productSchema = Schema({ 7 | name: { 8 | type: String, 9 | required: true, 10 | // minlength: 2, 11 | // maxlength: 50 12 | }, 13 | price: { 14 | type: Number, 15 | required: [true, "price must be exist"], 16 | min: 0.01 17 | }, 18 | active: { 19 | type: Boolean, 20 | default: true 21 | }, 22 | status: { 23 | type: String, 24 | enum: ["basic", "sale", "stock"], 25 | default: "basic" 26 | }, 27 | code: { 28 | type: String, 29 | required: true, 30 | unique: true, 31 | match: codeRegexp 32 | } 33 | }, {versionKey: false, timestamps: true}); 34 | 35 | const joiSchema = Joi.object({ 36 | name: Joi.string().required(), 37 | price: Joi.number().min(0.01).required(), 38 | active: Joi.bool(), 39 | status: Joi.string().valid("basic", "sale", "stock"), 40 | code: Joi.string().pattern(codeRegexp) 41 | }); 42 | 43 | const statusJoiSchema = Joi.object({ 44 | status: Joi.string().valid("basic", "sale", "stock").required() 45 | }) 46 | 47 | const Product = model("product", productSchema); 48 | 49 | module.exports = { 50 | Product, 51 | joiSchema, 52 | statusJoiSchema 53 | } -------------------------------------------------------------------------------- /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", 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.1", 17 | "joi": "^17.4.2", 18 | "mongoose": "^6.0.13", 19 | "morgan": "1.10.0", 20 | "uuid": "^8.3.2" 21 | }, 22 | "devDependencies": { 23 | "eslint": "^7.19.0", 24 | "eslint-config-standard": "^16.0.2", 25 | "eslint-plugin-import": "^2.22.1", 26 | "eslint-plugin-node": "^11.1.0", 27 | "eslint-plugin-promise": "^4.2.1", 28 | "nodemon": "2.0.7" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lesson-6/nodejs-homework-template-master/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {validation, ctrlWrapper} = require("../../middlewares"); 4 | const {joiSchema, statusJoiSchema} = require("../../models/product"); 5 | const {products: ctrl} = require("../../controllers") 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", ctrlWrapper(ctrl.getAll)); 10 | 11 | router.get("/:id", ctrlWrapper(ctrl.getById)); 12 | 13 | router.post("/", validation(joiSchema), ctrlWrapper(ctrl.add)); 14 | 15 | router.put("/:id", validation(joiSchema), ctrlWrapper(ctrl.updateById)); 16 | 17 | router.patch("/:id/status", validation(statusJoiSchema), ctrlWrapper(ctrl.updateStatus)); 18 | 19 | router.delete("/:id", ctrlWrapper(ctrl.removeById)); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /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: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.lhj89.mongodb.net/online_shop?retryWrites=true&w=majority 2 | SECRET_KEY=GHGSDFM23Tfgsfs3 3 | DB_USER=Bogdan 4 | DB_PASSWORD=pBje6ZbFRATcsTq 5 | DB_NAME=online_shop -------------------------------------------------------------------------------- /lesson-7/auth-example/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-7/auth-example/.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-7/auth-example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lesson-7/auth-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | require("dotenv").config(); 5 | 6 | const authRouter = require("./routes/api/auth"); 7 | const productsRouter = require("./routes/api/products"); 8 | 9 | const app = express() 10 | 11 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 12 | 13 | app.use(logger(formatsLogger)) 14 | app.use(cors()) 15 | app.use(express.json()) 16 | 17 | app.use("/api/auth", authRouter); 18 | app.use('/api/products', productsRouter); 19 | 20 | app.use((req, res) => { 21 | res.status(404).json({ message: 'Not found' }) 22 | }) 23 | 24 | app.use((err, req, res, next) => { 25 | const {status = 500, message = "Server error"} = err; 26 | res.status(status).json({ message: err.message }) 27 | }) 28 | 29 | module.exports = app 30 | -------------------------------------------------------------------------------- /lesson-7/auth-example/bin/server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const app = require('../app'); 4 | 5 | const {DB_HOST, PORT = 3000} = process.env; 6 | 7 | mongoose.connect(DB_HOST) 8 | .then(()=> app.listen(PORT)) 9 | .catch(error => { 10 | console.log(error.message); 11 | process.exit(1); 12 | }) 13 | 14 | 15 | -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/auth/index.js: -------------------------------------------------------------------------------- 1 | const register = require("./register"); 2 | const login = require("./login"); 3 | 4 | module.exports = { 5 | register, 6 | login 7 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/auth/login.js: -------------------------------------------------------------------------------- 1 | const {Unauthorized} = require("http-errors"); 2 | const jwt = require("jsonwebtoken"); 3 | // const bcrypt = require("bcryptjs"); 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}); 12 | if(!user || !user.comparePassword(password)){ 13 | throw new Unauthorized("Email or password is wrong"); 14 | } 15 | // const passCompare = bcrypt.compareSync(password, user.password); 16 | // if(!user || !passCompare){ 17 | // throw new Unauthorized("Email or password is wrong"); 18 | // } 19 | // if(!user){ 20 | // throw new Unauthorized(`Email ${email} not found`); 21 | // } 22 | // const passCompare = bcrypt.compareSync(password, user.password); 23 | // if(!passCompare){ 24 | // throw new Unauthorized("Password wrong"); 25 | // } 26 | const payload = { 27 | id: user._id 28 | }; 29 | const token = jwt.sign(payload, SECRET_KEY, {expiresIn: "1h"}); 30 | res.json({ 31 | status: "success", 32 | code: 200, 33 | data: { 34 | token 35 | } 36 | }) 37 | } 38 | 39 | module.exports = login; -------------------------------------------------------------------------------- /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 {name, email, password} = req.body; 8 | const user = await User.findOne({email}); 9 | if(user){ 10 | throw new Conflict(`User with ${email} already exist`) 11 | } 12 | const newUser = new User({name, email}); 13 | /* 14 | newUser = { 15 | name, 16 | email, 17 | setPassword(password){ 18 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)) 19 | } 20 | } 21 | */ 22 | newUser.setPassword(password); 23 | /* 24 | newUser = { 25 | name, 26 | email, 27 | password, 28 | setPassword(password){ 29 | this.passord = bcrypt.hashSync(password, bcrypt.genSaltSync(10)) 30 | } 31 | } 32 | */ 33 | newUser.save(); 34 | // const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 35 | // const result = await User.create({name, email, password: hashPassword}); 36 | res.status(201).json({ 37 | status: "success", 38 | code: 201, 39 | data: { 40 | user: { 41 | email, 42 | name 43 | } 44 | } 45 | }); 46 | } 47 | 48 | module.exports = register; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | const auth = require("./auth"); 3 | 4 | module.exports = { 5 | products, 6 | auth 7 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/products/add.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const add = async (req, res) => { 4 | const result = await Product.create(req.body); 5 | res.status(201).json({ 6 | status: "success", 7 | code: 201, 8 | data: { 9 | result 10 | } 11 | }) 12 | } 13 | 14 | module.exports = add; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/products/getAll.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const getAll = async (req, res) => { 4 | const products = await Product.find({}); 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | result: products 10 | } 11 | }); 12 | }; 13 | 14 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/products/getById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const getById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findById(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/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 | const updateStatus = require("./updateStatus"); 7 | 8 | module.exports = { 9 | getAll, 10 | getById, 11 | add, 12 | updateById, 13 | updateStatus, 14 | removeById 15 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/products/removeById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const removeById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndRemove(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | message: "product deleted", 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/products/updateById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndUpdate(id, req.body, {new: true}); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-7/auth-example/controllers/products/updateStatus.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateStatus = async (req, res) => { 6 | const { id } = req.params; 7 | const {status} = req.body; 8 | const result = await Product.findByIdAndUpdate(id, {status}, {new: true}); 9 | if (!result) { 10 | throw new NotFound(`Product with id=${id} not found`); 11 | } 12 | res.json({ 13 | status: "success", 14 | code: 200, 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = updateStatus; -------------------------------------------------------------------------------- /lesson-7/auth-example/env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | DB_USER= 3 | DB_PASSWORD= 4 | DB_NAME= -------------------------------------------------------------------------------- /lesson-7/auth-example/middlewares/ctrlWrapper.js: -------------------------------------------------------------------------------- 1 | const ctrlWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } catch (error) { 6 | next(error); 7 | } 8 | } 9 | } 10 | 11 | module.exports = ctrlWrapper; -------------------------------------------------------------------------------- /lesson-7/auth-example/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const ctrlWrapper = require("./ctrlWrapper"); 3 | 4 | module.exports = { 5 | validation, 6 | ctrlWrapper 7 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | error.status = 400; 6 | next(error); 7 | } 8 | next() 9 | } 10 | } 11 | 12 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-7/auth-example/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | const {User} = require("./user"); 3 | 4 | module.exports = { 5 | Product, 6 | User 7 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/models/product.js: -------------------------------------------------------------------------------- 1 | const {Schema, model} = require("mongoose"); 2 | const Joi = require("joi"); 3 | 4 | const codeRegexp = /^[0-9]{9}$/; 5 | 6 | const productSchema = Schema({ 7 | name: { 8 | type: String, 9 | required: true, 10 | // minlength: 2, 11 | // maxlength: 50 12 | }, 13 | price: { 14 | type: Number, 15 | required: [true, "price must be exist"], 16 | min: 0.01 17 | }, 18 | active: { 19 | type: Boolean, 20 | default: true 21 | }, 22 | status: { 23 | type: String, 24 | enum: ["basic", "sale", "stock"], 25 | default: "basic" 26 | }, 27 | code: { 28 | type: String, 29 | required: true, 30 | unique: true, 31 | match: codeRegexp 32 | } 33 | }, {versionKey: false, timestamps: true}); 34 | 35 | const joiSchema = Joi.object({ 36 | name: Joi.string().required(), 37 | price: Joi.number().min(0.01).required(), 38 | active: Joi.bool(), 39 | status: Joi.string().valid("basic", "sale", "stock"), 40 | code: Joi.string().pattern(codeRegexp) 41 | }); 42 | 43 | const statusJoiSchema = Joi.object({ 44 | status: Joi.string().valid("basic", "sale", "stock").required() 45 | }) 46 | 47 | const Product = model("product", productSchema); 48 | 49 | module.exports = { 50 | Product, 51 | joiSchema, 52 | statusJoiSchema 53 | } -------------------------------------------------------------------------------- /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 | name: { 7 | type: String, 8 | required: true 9 | }, 10 | email: { 11 | type: String, 12 | required: true, 13 | unique: true 14 | }, 15 | password: { 16 | type: String, 17 | required: true, 18 | minlength: 6 19 | } 20 | }, {versionKey: false, timestamps: true}); 21 | 22 | userSchema.methods.setPassword = function(password){ 23 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 24 | } 25 | 26 | userSchema.methods.comparePassword = function(password){ 27 | return bcrypt.compareSync(password, this.password); 28 | } 29 | 30 | const joiRegisterSchema = Joi.object({ 31 | name: Joi.string().required(), 32 | email: Joi.string().required(), 33 | password: Joi.string().min(6).required() 34 | }) 35 | 36 | const joiLoginSchema = Joi.object({ 37 | email: Joi.string().required(), 38 | password: Joi.string().min(6).required() 39 | }) 40 | 41 | 42 | const User = model("user", userSchema); 43 | 44 | module.exports = { 45 | User, 46 | joiRegisterSchema, 47 | joiLoginSchema 48 | } -------------------------------------------------------------------------------- /lesson-7/auth-example/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-7/auth-example/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 | "bcryptjs": "^2.4.3", 13 | "cors": "2.8.5", 14 | "cross-env": "7.0.3", 15 | "dotenv": "^10.0.0", 16 | "express": "4.17.1", 17 | "http-errors": "^1.8.1", 18 | "joi": "^17.4.2", 19 | "jsonwebtoken": "^8.5.1", 20 | "mongoose": "^6.0.13", 21 | "morgan": "1.10.0", 22 | "uuid": "^8.3.2" 23 | }, 24 | "devDependencies": { 25 | "eslint": "^7.19.0", 26 | "eslint-config-standard": "^16.0.2", 27 | "eslint-plugin-import": "^2.22.1", 28 | "eslint-plugin-node": "^11.1.0", 29 | "eslint-plugin-promise": "^4.2.1", 30 | "nodemon": "2.0.7" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lesson-7/auth-example/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-7/auth-example/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {validation, ctrlWrapper} = require("../../middlewares"); 4 | const {auth: ctrl} = require("../../controllers"); 5 | const {joiRegisterSchema, joiLoginSchema} = require("../../models/user"); 6 | 7 | const router = express.Router(); 8 | 9 | router.post("/register", validation(joiRegisterSchema), ctrlWrapper(ctrl.register)); 10 | // router.post("/signup") 11 | router.post("/login", validation(joiLoginSchema), ctrlWrapper(ctrl.login)); 12 | // router.post("/signin") 13 | module.exports = router; -------------------------------------------------------------------------------- /lesson-7/auth-example/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {validation, ctrlWrapper} = require("../../middlewares"); 4 | const {joiSchema, statusJoiSchema} = require("../../models/product"); 5 | const {products: ctrl} = require("../../controllers") 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", ctrlWrapper(ctrl.getAll)); 10 | 11 | router.get("/:id", ctrlWrapper(ctrl.getById)); 12 | 13 | router.post("/", validation(joiSchema), ctrlWrapper(ctrl.add)); 14 | 15 | router.put("/:id", validation(joiSchema), ctrlWrapper(ctrl.updateById)); 16 | 17 | router.patch("/:id/status", validation(statusJoiSchema), ctrlWrapper(ctrl.updateStatus)); 18 | 19 | router.delete("/:id", ctrlWrapper(ctrl.removeById)); 20 | 21 | 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 | // console.log(bcrypt.genSaltSync(10)); 6 | const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 7 | // console.log(hashPassword); 8 | 9 | const result1 = bcrypt.compareSync(password, hashPassword); 10 | console.log(result1); 11 | 12 | const result2 = bcrypt.compareSync("passwort", hashPassword); 13 | console.log(result2); 14 | 15 | -------------------------------------------------------------------------------- /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/jsonwebtoken-example/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package-lock.json 3 | yarn.lock 4 | .yarn.error 5 | node_modules/ -------------------------------------------------------------------------------- /lesson-7/jsonwebtoken-example/app.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | 3 | const SECRET_KEY = "2refaasdfhgsdg313fd"; 4 | 5 | const payload = { 6 | id: "61a52562a6476e7590d7d5f6" 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 result = jwt.verify(token, SECRET_KEY); 17 | // console.log(result); 18 | const result2 = jwt.verify(`${token}22`, SECRET_KEY); 19 | } catch (error) { 20 | console.log(error.message); 21 | } -------------------------------------------------------------------------------- /lesson-7/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-7/slides/HTTP-common-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/HTTP-common-schema.jpg -------------------------------------------------------------------------------- /lesson-7/slides/HTTP-personal-request-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/HTTP-personal-request-schema.jpg -------------------------------------------------------------------------------- /lesson-7/slides/JWT-token-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/JWT-token-schema.jpg -------------------------------------------------------------------------------- /lesson-7/slides/frontend-backend-requests-with-token.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/frontend-backend-requests-with-token.jpg -------------------------------------------------------------------------------- /lesson-7/slides/hash-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/hash-schema.jpg -------------------------------------------------------------------------------- /lesson-7/slides/jwt-token-real-life-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/jwt-token-real-life-example.jpg -------------------------------------------------------------------------------- /lesson-7/slides/logout-examples.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/logout-examples.jpg -------------------------------------------------------------------------------- /lesson-7/slides/process.env-and-deploy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/process.env-and-deploy.jpg -------------------------------------------------------------------------------- /lesson-7/slides/register-auth-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/register-auth-steps.jpg -------------------------------------------------------------------------------- /lesson-7/slides/reigster-auth-create-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-7/slides/reigster-auth-create-steps.jpg -------------------------------------------------------------------------------- /lesson-8/auth-example/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.lhj89.mongodb.net/online_shop?retryWrites=true&w=majority 2 | SECRET_KEY=GHGSDFM23Tfgsfs3 3 | DB_USER=Bogdan 4 | DB_PASSWORD=pBje6ZbFRATcsTq 5 | DB_NAME=online_shop -------------------------------------------------------------------------------- /lesson-8/auth-example/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-8/auth-example/.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-8/auth-example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lesson-8/auth-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | require("dotenv").config(); 5 | 6 | const authRouter = require("./routes/api/auth"); 7 | const usersRouter = require("./routes/api/users"); 8 | const productsRouter = require("./routes/api/products"); 9 | 10 | const app = express() 11 | 12 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 13 | 14 | app.use(logger(formatsLogger)) 15 | app.use(cors()) 16 | app.use(express.json()) 17 | 18 | app.use("/api/auth", authRouter); 19 | app.use("/api/users", usersRouter); 20 | app.use('/api/products', productsRouter); 21 | 22 | app.use((req, res) => { 23 | res.status(404).json({ message: 'Not found' }) 24 | }) 25 | 26 | app.use((err, req, res, next) => { 27 | const {status = 500, message = "Server error"} = err; 28 | res.status(status).json({ message: err.message }) 29 | }) 30 | 31 | module.exports = app 32 | -------------------------------------------------------------------------------- /lesson-8/auth-example/bin/server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const app = require('../app'); 4 | 5 | const {DB_HOST, PORT = 3000} = process.env; 6 | 7 | mongoose.connect(DB_HOST) 8 | .then(()=> app.listen(PORT)) 9 | .catch(error => { 10 | console.log(error.message); 11 | process.exit(1); 12 | }) 13 | 14 | 15 | -------------------------------------------------------------------------------- /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 {Unauthorized} = require("http-errors"); 2 | const jwt = require("jsonwebtoken"); 3 | // const bcrypt = require("bcryptjs"); 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}); 12 | if(!user || !user.comparePassword(password)){ 13 | throw new Unauthorized("Email or password is wrong"); 14 | } 15 | // const passCompare = bcrypt.compareSync(password, user.password); 16 | // if(!user || !passCompare){ 17 | // throw new Unauthorized("Email or password is wrong"); 18 | // } 19 | // if(!user){ 20 | // throw new Unauthorized(`Email ${email} not found`); 21 | // } 22 | // const passCompare = bcrypt.compareSync(password, user.password); 23 | // if(!passCompare){ 24 | // throw new Unauthorized("Password wrong"); 25 | // } 26 | const payload = { 27 | id: user._id 28 | }; 29 | const token = jwt.sign(payload, SECRET_KEY, {expiresIn: "1h"}); 30 | await User.findByIdAndUpdate(user._id, {token}); 31 | res.json({ 32 | status: "success", 33 | code: 200, 34 | data: { 35 | token 36 | } 37 | }) 38 | } 39 | 40 | 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.status(204).json(); 7 | } 8 | 9 | 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 {name, email, password} = req.body; 8 | const user = await User.findOne({email}); 9 | if(user){ 10 | throw new Conflict(`User with ${email} already exist`) 11 | } 12 | const newUser = new User({name, email}); 13 | /* 14 | newUser = { 15 | name, 16 | email, 17 | setPassword(password){ 18 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)) 19 | } 20 | } 21 | */ 22 | newUser.setPassword(password); 23 | /* 24 | newUser = { 25 | name, 26 | email, 27 | password, 28 | setPassword(password){ 29 | this.passord = bcrypt.hashSync(password, bcrypt.genSaltSync(10)) 30 | } 31 | } 32 | */ 33 | newUser.save(); 34 | // const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 35 | // const result = await User.create({name, email, password: hashPassword}); 36 | res.status(201).json({ 37 | status: "success", 38 | code: 201, 39 | data: { 40 | user: { 41 | email, 42 | name 43 | } 44 | } 45 | }); 46 | } 47 | 48 | module.exports = register; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | const auth = require("./auth"); 3 | const users = require("./users"); 4 | 5 | module.exports = { 6 | products, 7 | auth, 8 | users 9 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/products/add.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const add = async (req, res) => { 4 | const {_id} = req.user; 5 | const result = await Product.create({...req.body, owner: _id}); 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/products/getAll.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const getAll = async (req, res) => { 4 | const {_id} = req.user; 5 | const {page = 1, limit = 10} = req.query; 6 | const skip = (page - 1) * limit; 7 | const products = await Product.find({owner: _id}, "", {skip, limit: Number(limit)}).populate("owner", "_id name email"); 8 | 9 | res.json({ 10 | status: "success", 11 | code: 200, 12 | data: { 13 | result: products 14 | } 15 | }); 16 | }; 17 | 18 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/products/getById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const getById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findById(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/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 | const updateStatus = require("./updateStatus"); 7 | 8 | module.exports = { 9 | getAll, 10 | getById, 11 | add, 12 | updateById, 13 | updateStatus, 14 | removeById 15 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/products/removeById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const removeById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndRemove(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | message: "product deleted", 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/products/updateById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndUpdate(id, req.body, {new: true}); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/products/updateStatus.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateStatus = async (req, res) => { 6 | const { id } = req.params; 7 | const {status} = req.body; 8 | const result = await Product.findByIdAndUpdate(id, {status}, {new: true}); 9 | if (!result) { 10 | throw new NotFound(`Product with id=${id} not found`); 11 | } 12 | res.json({ 13 | status: "success", 14 | code: 200, 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = updateStatus; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/users/getCurrent.js: -------------------------------------------------------------------------------- 1 | const {User} = require("../../models"); 2 | 3 | const getCurrent = async(req, res)=> { 4 | const {name, email} = req.user; 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | user: { 10 | name, 11 | email 12 | } 13 | 14 | } 15 | }) 16 | } 17 | 18 | module.exports = getCurrent; -------------------------------------------------------------------------------- /lesson-8/auth-example/controllers/users/index.js: -------------------------------------------------------------------------------- 1 | const getCurrent = require("./getCurrent"); 2 | 3 | module.exports = { 4 | getCurrent 5 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | DB_USER= 3 | DB_PASSWORD= 4 | DB_NAME= -------------------------------------------------------------------------------- /lesson-8/auth-example/middlewares/ctrlWrapper.js: -------------------------------------------------------------------------------- 1 | const ctrlWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } catch (error) { 6 | next(error); 7 | } 8 | } 9 | } 10 | 11 | module.exports = ctrlWrapper; -------------------------------------------------------------------------------- /lesson-8/auth-example/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const ctrlWrapper = require("./ctrlWrapper"); 3 | const auth = require("./auth"); 4 | 5 | module.exports = { 6 | validation, 7 | ctrlWrapper, 8 | auth 9 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | error.status = 400; 6 | next(error); 7 | } 8 | next() 9 | } 10 | } 11 | 12 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-8/auth-example/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | const {User} = require("./user"); 3 | 4 | module.exports = { 5 | Product, 6 | User 7 | } -------------------------------------------------------------------------------- /lesson-8/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 | name: { 7 | type: String, 8 | required: true 9 | }, 10 | email: { 11 | type: String, 12 | required: true, 13 | unique: true 14 | }, 15 | password: { 16 | type: String, 17 | required: true, 18 | minlength: 6 19 | }, 20 | token: { 21 | type: String, 22 | default: null 23 | } 24 | }, {versionKey: false, timestamps: true}); 25 | 26 | userSchema.methods.setPassword = function(password){ 27 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 28 | } 29 | 30 | userSchema.methods.comparePassword = function(password){ 31 | return bcrypt.compareSync(password, this.password); 32 | } 33 | 34 | const joiRegisterSchema = Joi.object({ 35 | name: Joi.string().required(), 36 | email: Joi.string().required(), 37 | password: Joi.string().min(6).required() 38 | }) 39 | 40 | const joiLoginSchema = Joi.object({ 41 | email: Joi.string().required(), 42 | password: Joi.string().min(6).required() 43 | }) 44 | 45 | 46 | const User = model("user", userSchema); 47 | 48 | module.exports = { 49 | User, 50 | joiRegisterSchema, 51 | joiLoginSchema 52 | } -------------------------------------------------------------------------------- /lesson-8/auth-example/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-8/auth-example/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 | "bcryptjs": "^2.4.3", 13 | "cors": "2.8.5", 14 | "cross-env": "7.0.3", 15 | "dotenv": "^10.0.0", 16 | "express": "4.17.1", 17 | "http-errors": "^1.8.1", 18 | "joi": "^17.4.2", 19 | "jsonwebtoken": "^8.5.1", 20 | "mongoose": "^6.0.13", 21 | "morgan": "1.10.0", 22 | "uuid": "^8.3.2" 23 | }, 24 | "devDependencies": { 25 | "eslint": "^7.19.0", 26 | "eslint-config-standard": "^16.0.2", 27 | "eslint-plugin-import": "^2.22.1", 28 | "eslint-plugin-node": "^11.1.0", 29 | "eslint-plugin-promise": "^4.2.1", 30 | "nodemon": "2.0.7" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lesson-8/auth-example/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-8/auth-example/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, validation, ctrlWrapper} = require("../../middlewares"); 4 | const {auth: ctrl} = require("../../controllers"); 5 | const {joiRegisterSchema, joiLoginSchema} = require("../../models/user"); 6 | 7 | const router = express.Router(); 8 | 9 | router.post("/register", validation(joiRegisterSchema), ctrlWrapper(ctrl.register)); 10 | // router.post("/signup") 11 | router.post("/login", validation(joiLoginSchema), ctrlWrapper(ctrl.login)); 12 | // router.post("/signin") 13 | router.get("/logout", auth, ctrlWrapper(ctrl.logout)); 14 | // router.get("/signout") 15 | module.exports = router; -------------------------------------------------------------------------------- /lesson-8/auth-example/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, validation, ctrlWrapper} = require("../../middlewares"); 4 | const {joiSchema, statusJoiSchema} = require("../../models/product"); 5 | const {products: ctrl} = require("../../controllers") 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", auth, ctrlWrapper(ctrl.getAll)); 10 | 11 | router.get("/:id", ctrlWrapper(ctrl.getById)); 12 | 13 | router.post("/", auth, validation(joiSchema), ctrlWrapper(ctrl.add)); 14 | 15 | router.put("/:id", validation(joiSchema), ctrlWrapper(ctrl.updateById)); 16 | 17 | router.patch("/:id/status", validation(statusJoiSchema), ctrlWrapper(ctrl.updateStatus)); 18 | 19 | router.delete("/:id", ctrlWrapper(ctrl.removeById)); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /lesson-8/auth-example/routes/api/users.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, ctrlWrapper} = require("../../middlewares"); 4 | const {users: ctrl} = require("../../controllers"); 5 | 6 | const router = express.Router(); 7 | 8 | router.get("/current", auth, ctrlWrapper(ctrl.getCurrent)); 9 | 10 | module.exports = router; -------------------------------------------------------------------------------- /lesson-8/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson-8/slides/HTTP-common-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/HTTP-common-schema.jpg -------------------------------------------------------------------------------- /lesson-8/slides/HTTP-personal-request-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/HTTP-personal-request-schema.jpg -------------------------------------------------------------------------------- /lesson-8/slides/JWT-token-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/JWT-token-schema.jpg -------------------------------------------------------------------------------- /lesson-8/slides/frontend-backend-requests-with-token.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/frontend-backend-requests-with-token.jpg -------------------------------------------------------------------------------- /lesson-8/slides/hash-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/hash-schema.jpg -------------------------------------------------------------------------------- /lesson-8/slides/jwt-token-real-life-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/jwt-token-real-life-example.jpg -------------------------------------------------------------------------------- /lesson-8/slides/logout-examples.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/logout-examples.jpg -------------------------------------------------------------------------------- /lesson-8/slides/process.env-and-deploy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/process.env-and-deploy.jpg -------------------------------------------------------------------------------- /lesson-8/slides/register-auth-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/register-auth-steps.jpg -------------------------------------------------------------------------------- /lesson-8/slides/reigster-auth-create-steps.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-8/slides/reigster-auth-create-steps.jpg -------------------------------------------------------------------------------- /lesson-9/2085-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-9/2085-1.png -------------------------------------------------------------------------------- /lesson-9/auth-example/.env: -------------------------------------------------------------------------------- 1 | DB_HOST=mongodb+srv://Bogdan:pBje6ZbFRATcsTq@cluster0.lhj89.mongodb.net/online_shop?retryWrites=true&w=majority 2 | SECRET_KEY=GHGSDFM23Tfgsfs3 3 | DB_USER=Bogdan 4 | DB_PASSWORD=pBje6ZbFRATcsTq 5 | DB_NAME=online_shop -------------------------------------------------------------------------------- /lesson-9/auth-example/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /lesson-9/auth-example/.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-9/auth-example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lesson-9/auth-example/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const logger = require('morgan') 3 | const cors = require('cors') 4 | require("dotenv").config(); 5 | 6 | const authRouter = require("./routes/api/auth"); 7 | const usersRouter = require("./routes/api/users"); 8 | const productsRouter = require("./routes/api/products"); 9 | 10 | const app = express() 11 | 12 | const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short' 13 | 14 | app.use(logger(formatsLogger)) 15 | app.use(cors()) 16 | app.use(express.json()) 17 | app.use(express.static("public")) 18 | 19 | app.use("/api/auth", authRouter); 20 | app.use("/api/users", usersRouter); 21 | app.use('/api/products', productsRouter); 22 | 23 | app.use((req, res) => { 24 | res.status(404).json({ message: 'Not found' }) 25 | }) 26 | 27 | app.use((err, req, res, next) => { 28 | const {status = 500, message = "Server error"} = err; 29 | res.status(status).json({ message: err.message }) 30 | }) 31 | 32 | module.exports = app 33 | -------------------------------------------------------------------------------- /lesson-9/auth-example/bin/server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const app = require('../app'); 4 | 5 | const {DB_HOST, PORT = 3000} = process.env; 6 | 7 | mongoose.connect(DB_HOST) 8 | .then(()=> app.listen(PORT)) 9 | .catch(error => { 10 | console.log(error.message); 11 | process.exit(1); 12 | }) 13 | 14 | 15 | -------------------------------------------------------------------------------- /lesson-9/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-9/auth-example/controllers/auth/login.js: -------------------------------------------------------------------------------- 1 | const {Unauthorized} = require("http-errors"); 2 | const jwt = require("jsonwebtoken"); 3 | // const bcrypt = require("bcryptjs"); 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}); 12 | if(!user || !user.comparePassword(password)){ 13 | throw new Unauthorized("Email or password is wrong"); 14 | } 15 | // const passCompare = bcrypt.compareSync(password, user.password); 16 | // if(!user || !passCompare){ 17 | // throw new Unauthorized("Email or password is wrong"); 18 | // } 19 | // if(!user){ 20 | // throw new Unauthorized(`Email ${email} not found`); 21 | // } 22 | // const passCompare = bcrypt.compareSync(password, user.password); 23 | // if(!passCompare){ 24 | // throw new Unauthorized("Password wrong"); 25 | // } 26 | const payload = { 27 | id: user._id 28 | }; 29 | const token = jwt.sign(payload, SECRET_KEY, {expiresIn: "1h"}); 30 | await User.findByIdAndUpdate(user._id, {token}); 31 | res.json({ 32 | status: "success", 33 | code: 200, 34 | data: { 35 | token 36 | } 37 | }) 38 | } 39 | 40 | module.exports = login; -------------------------------------------------------------------------------- /lesson-9/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.status(204).json(); 7 | } 8 | 9 | module.exports = logout; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/auth/register.js: -------------------------------------------------------------------------------- 1 | const {Conflict} = require("http-errors"); 2 | const gravatar = require("gravatar"); 3 | 4 | const {User} = require("../../models"); 5 | 6 | const register = async(req, res)=> { 7 | const {name, email, password} = req.body; 8 | const user = await User.findOne({email}); 9 | if(user){ 10 | throw new Conflict(`User with ${email} already exist`) 11 | } 12 | const avatarURL = gravatar.url(email); 13 | const newUser = new User({name, email, avatarURL}); 14 | 15 | newUser.setPassword(password); 16 | 17 | newUser.save(); 18 | 19 | res.status(201).json({ 20 | status: "success", 21 | code: 201, 22 | data: { 23 | user: { 24 | name, 25 | email, 26 | avatarURL 27 | } 28 | } 29 | }); 30 | } 31 | 32 | module.exports = register; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/index.js: -------------------------------------------------------------------------------- 1 | const products = require("./products"); 2 | const auth = require("./auth"); 3 | const users = require("./users"); 4 | 5 | module.exports = { 6 | products, 7 | auth, 8 | users 9 | } -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/products/add.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const add = async (req, res) => { 4 | const {_id} = req.user; 5 | const result = await Product.create({...req.body, owner: _id}); 6 | res.status(201).json({ 7 | status: "success", 8 | code: 201, 9 | data: { 10 | result 11 | } 12 | }) 13 | } 14 | 15 | module.exports = add; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/products/getAll.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("../../models"); 2 | 3 | const getAll = async (req, res) => { 4 | const {_id} = req.user; 5 | const {page = 1, limit = 10} = req.query; 6 | const skip = (page - 1) * limit; 7 | const products = await Product.find({owner: _id}, "", {skip, limit: Number(limit)}).populate("owner", "_id name email"); 8 | 9 | res.json({ 10 | status: "success", 11 | code: 200, 12 | data: { 13 | result: products 14 | } 15 | }); 16 | }; 17 | 18 | module.exports = getAll; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/products/getById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const getById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findById(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = getById; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/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 | const updateStatus = require("./updateStatus"); 7 | 8 | module.exports = { 9 | getAll, 10 | getById, 11 | add, 12 | updateById, 13 | updateStatus, 14 | removeById 15 | } -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/products/removeById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const removeById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndRemove(id); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | message: "product deleted", 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = removeById; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/products/updateById.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateById = async (req, res) => { 6 | const { id } = req.params; 7 | const result = await Product.findByIdAndUpdate(id, req.body, {new: true}); 8 | if (!result) { 9 | throw new NotFound(`Product with id=${id} not found`); 10 | } 11 | res.json({ 12 | status: "success", 13 | code: 200, 14 | data: { 15 | result 16 | } 17 | }) 18 | } 19 | 20 | module.exports = updateById; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/products/updateStatus.js: -------------------------------------------------------------------------------- 1 | const { NotFound } = require("http-errors"); 2 | 3 | const {Product} = require("../../models"); 4 | 5 | const updateStatus = async (req, res) => { 6 | const { id } = req.params; 7 | const {status} = req.body; 8 | const result = await Product.findByIdAndUpdate(id, {status}, {new: true}); 9 | if (!result) { 10 | throw new NotFound(`Product with id=${id} not found`); 11 | } 12 | res.json({ 13 | status: "success", 14 | code: 200, 15 | data: { 16 | result 17 | } 18 | }) 19 | } 20 | 21 | module.exports = updateStatus; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/users/getCurrent.js: -------------------------------------------------------------------------------- 1 | const {User} = require("../../models"); 2 | 3 | const getCurrent = async(req, res)=> { 4 | const {name, email} = req.user; 5 | res.json({ 6 | status: "success", 7 | code: 200, 8 | data: { 9 | user: { 10 | name, 11 | email 12 | } 13 | 14 | } 15 | }) 16 | } 17 | 18 | module.exports = getCurrent; -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/users/index.js: -------------------------------------------------------------------------------- 1 | const getCurrent = require("./getCurrent"); 2 | const updateAvatar = require("./updateAvatar"); 3 | 4 | module.exports = { 5 | getCurrent, 6 | updateAvatar 7 | } -------------------------------------------------------------------------------- /lesson-9/auth-example/controllers/users/updateAvatar.js: -------------------------------------------------------------------------------- 1 | const {User} = require("../../models"); 2 | const path = require("path"); 3 | const fs = require("fs/promises"); 4 | 5 | const avatarsDir = path.join(__dirname, "../../", "public", "avatars"); 6 | 7 | const updateAvatar = async(req, res)=> { 8 | const {path: tempUpload, originalname} = req.file; 9 | const {_id: id} = req.user; 10 | const imageName = `${id}_${originalname}`; 11 | try { 12 | const resultUpload = path.join(avatarsDir, imageName); 13 | await fs.rename(tempUpload, resultUpload); 14 | const avatarURL = path.join("public", "avatars", imageName); 15 | await User.findByIdAndUpdate(req.user._id, {avatarURL}); 16 | res.json({avatarURL}); 17 | } catch (error) { 18 | await fs.unlink(tempUpload); 19 | throw error; 20 | } 21 | }; 22 | 23 | module.exports = updateAvatar; -------------------------------------------------------------------------------- /lesson-9/auth-example/env.example: -------------------------------------------------------------------------------- 1 | DB_HOST= 2 | DB_USER= 3 | DB_PASSWORD= 4 | DB_NAME= -------------------------------------------------------------------------------- /lesson-9/auth-example/middlewares/ctrlWrapper.js: -------------------------------------------------------------------------------- 1 | const ctrlWrapper = (ctrl)=> { 2 | return async(req, res, next)=> { 3 | try { 4 | await ctrl(req, res, next); 5 | } catch (error) { 6 | next(error); 7 | } 8 | } 9 | } 10 | 11 | module.exports = ctrlWrapper; -------------------------------------------------------------------------------- /lesson-9/auth-example/middlewares/index.js: -------------------------------------------------------------------------------- 1 | const validation = require("./validation"); 2 | const ctrlWrapper = require("./ctrlWrapper"); 3 | const auth = require("./auth"); 4 | const upload = require("./upload"); 5 | 6 | module.exports = { 7 | validation, 8 | ctrlWrapper, 9 | auth, 10 | upload 11 | } -------------------------------------------------------------------------------- /lesson-9/auth-example/middlewares/upload.js: -------------------------------------------------------------------------------- 1 | const multer = require("multer"); 2 | const path = require("path"); 3 | 4 | const tempDir = path.join(__dirname, "../", "temp"); 5 | 6 | const multerConfig = 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: 2048 15 | } 16 | }) 17 | 18 | const upload = multer({ 19 | storage: multerConfig 20 | }) 21 | 22 | module.exports = upload; -------------------------------------------------------------------------------- /lesson-9/auth-example/middlewares/validation.js: -------------------------------------------------------------------------------- 1 | const validation = (schema)=> { 2 | return (req, res, next)=> { 3 | const {error} = schema.validate(req.body); 4 | if(error){ 5 | error.status = 400; 6 | next(error); 7 | } 8 | next() 9 | } 10 | } 11 | 12 | module.exports = validation; -------------------------------------------------------------------------------- /lesson-9/auth-example/models/index.js: -------------------------------------------------------------------------------- 1 | const {Product} = require("./product"); 2 | const {User} = require("./user"); 3 | 4 | module.exports = { 5 | Product, 6 | User 7 | } -------------------------------------------------------------------------------- /lesson-9/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 | name: { 7 | type: String, 8 | required: true 9 | }, 10 | email: { 11 | type: String, 12 | required: true, 13 | unique: true 14 | }, 15 | password: { 16 | type: String, 17 | required: true, 18 | minlength: 6 19 | }, 20 | token: { 21 | type: String, 22 | default: null 23 | }, 24 | avatarURL: { 25 | type: String, 26 | required: true 27 | } 28 | }, {versionKey: false, timestamps: true}); 29 | 30 | userSchema.methods.setPassword = function(password){ 31 | this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10)); 32 | } 33 | 34 | userSchema.methods.comparePassword = function(password){ 35 | return bcrypt.compareSync(password, this.password); 36 | } 37 | 38 | const joiRegisterSchema = Joi.object({ 39 | name: Joi.string().required(), 40 | email: Joi.string().required(), 41 | password: Joi.string().min(6).required() 42 | }) 43 | 44 | const joiLoginSchema = Joi.object({ 45 | email: Joi.string().required(), 46 | password: Joi.string().min(6).required() 47 | }) 48 | 49 | 50 | const User = model("user", userSchema); 51 | 52 | module.exports = { 53 | User, 54 | joiRegisterSchema, 55 | joiLoginSchema 56 | } -------------------------------------------------------------------------------- /lesson-9/auth-example/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["node_modules", "model/contacts.json"] 3 | } 4 | -------------------------------------------------------------------------------- /lesson-9/auth-example/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 | "bcryptjs": "^2.4.3", 13 | "cors": "2.8.5", 14 | "cross-env": "7.0.3", 15 | "dotenv": "^10.0.0", 16 | "express": "4.17.1", 17 | "gravatar": "^1.8.2", 18 | "http-errors": "^1.8.1", 19 | "joi": "^17.4.2", 20 | "jsonwebtoken": "^8.5.1", 21 | "mongoose": "^6.0.13", 22 | "morgan": "1.10.0", 23 | "multer": "^1.4.4", 24 | "uuid": "^8.3.2" 25 | }, 26 | "devDependencies": { 27 | "eslint": "^7.19.0", 28 | "eslint-config-standard": "^16.0.2", 29 | "eslint-plugin-import": "^2.22.1", 30 | "eslint-plugin-node": "^11.1.0", 31 | "eslint-plugin-promise": "^4.2.1", 32 | "nodemon": "2.0.7" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lesson-9/auth-example/public/avatars/61afac845d2f14829dd3b79a_2085-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-9/auth-example/public/avatars/61afac845d2f14829dd3b79a_2085-1.png -------------------------------------------------------------------------------- /lesson-9/auth-example/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-9/auth-example/routes/api/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, validation, ctrlWrapper} = require("../../middlewares"); 4 | const {auth: ctrl} = require("../../controllers"); 5 | const {joiRegisterSchema, joiLoginSchema} = require("../../models/user"); 6 | 7 | const router = express.Router(); 8 | 9 | router.post("/register", validation(joiRegisterSchema), ctrlWrapper(ctrl.register)); 10 | // router.post("/signup") 11 | router.post("/login", validation(joiLoginSchema), ctrlWrapper(ctrl.login)); 12 | // router.post("/signin") 13 | router.get("/logout", auth, ctrlWrapper(ctrl.logout)); 14 | // router.get("/signout") 15 | module.exports = router; -------------------------------------------------------------------------------- /lesson-9/auth-example/routes/api/products.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, validation, ctrlWrapper} = require("../../middlewares"); 4 | const {joiSchema, statusJoiSchema} = require("../../models/product"); 5 | const {products: ctrl} = require("../../controllers") 6 | 7 | const router = express.Router(); 8 | 9 | router.get("/", auth, ctrlWrapper(ctrl.getAll)); 10 | 11 | router.get("/:id", ctrlWrapper(ctrl.getById)); 12 | 13 | router.post("/", auth, validation(joiSchema), ctrlWrapper(ctrl.add)); 14 | 15 | router.put("/:id", validation(joiSchema), ctrlWrapper(ctrl.updateById)); 16 | 17 | router.patch("/:id/status", validation(statusJoiSchema), ctrlWrapper(ctrl.updateStatus)); 18 | 19 | router.delete("/:id", ctrlWrapper(ctrl.removeById)); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /lesson-9/auth-example/routes/api/users.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const {auth, upload, ctrlWrapper} = require("../../middlewares"); 4 | const {users: ctrl} = require("../../controllers"); 5 | 6 | const router = express.Router(); 7 | 8 | router.get("/current", auth, ctrlWrapper(ctrl.getCurrent)); 9 | router.patch("/avatars", auth, upload.single("avatar"), ctrlWrapper(ctrl.updateAvatar)); 10 | 11 | module.exports = router; -------------------------------------------------------------------------------- /lesson-9/auth-example/temp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-9/auth-example/temp/.gitkeep -------------------------------------------------------------------------------- /lesson-9/multer-example/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ -------------------------------------------------------------------------------- /lesson-9/multer-example/frontend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | 12 | 25 | 26 | -------------------------------------------------------------------------------- /lesson-9/multer-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | 12 | 13 |
14 | 23 | 24 | -------------------------------------------------------------------------------- /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.4", 21 | "uuid": "^8.3.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lesson-9/multer-example/public/products/2085-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-9/multer-example/public/products/2085-1.png -------------------------------------------------------------------------------- /lesson-9/multer-example/temp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-9/multer-example/temp/.gitkeep -------------------------------------------------------------------------------- /lesson-9/slides/multer-work-schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BogdanLyamzin/33-nodejs/eb9e1a04903e3f65ec35db4c4f18c59e2b8229f4/lesson-9/slides/multer-work-schema.jpg --------------------------------------------------------------------------------