├── lesson-6 ├── demo │ ├── server │ │ ├── src │ │ │ ├── core │ │ │ │ ├── index.js │ │ │ │ └── errors-check │ │ │ │ │ ├── index.js │ │ │ │ │ ├── order.js │ │ │ │ │ ├── product.js │ │ │ │ │ └── user.js │ │ │ ├── domain │ │ │ │ ├── index.js │ │ │ │ ├── user │ │ │ │ │ ├── get.js │ │ │ │ │ ├── create.js │ │ │ │ │ ├── delete.js │ │ │ │ │ ├── getAll.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── update.js │ │ │ │ └── db │ │ │ │ │ ├── connect-db.js │ │ │ │ │ ├── middleware │ │ │ │ │ └── timestamp.js │ │ │ │ │ └── schemas │ │ │ │ │ └── user.js │ │ │ ├── modules │ │ │ │ ├── app.js │ │ │ │ └── chat │ │ │ │ │ ├── templates │ │ │ │ │ ├── chatrooms.js │ │ │ │ │ └── users.js │ │ │ │ │ ├── chatroom-manager.js │ │ │ │ │ ├── chatroom.js │ │ │ │ │ ├── init-chat.js │ │ │ │ │ ├── client-manager.js │ │ │ │ │ └── handlers.js │ │ │ ├── routes │ │ │ │ ├── main │ │ │ │ │ └── main.js │ │ │ │ ├── user │ │ │ │ │ ├── get-all-users.js │ │ │ │ │ ├── delete-user.js │ │ │ │ │ ├── get-user.js │ │ │ │ │ ├── create-user.js │ │ │ │ │ └── update-user.js │ │ │ │ ├── image │ │ │ │ │ ├── get-image.js │ │ │ │ │ └── save-image-multipart.js │ │ │ │ └── router.js │ │ │ ├── controller │ │ │ │ ├── main │ │ │ │ │ └── main.js │ │ │ │ ├── users │ │ │ │ │ ├── get-all-users.js │ │ │ │ │ ├── delete-user.js │ │ │ │ │ ├── get-user.js │ │ │ │ │ ├── create-user.js │ │ │ │ │ └── update-user.js │ │ │ │ ├── image │ │ │ │ │ ├── get-image.js │ │ │ │ │ └── save-image-multipart.js │ │ │ │ └── index.js │ │ │ ├── db │ │ │ │ ├── connect-db.js │ │ │ │ ├── middleware │ │ │ │ │ └── timestamp.js │ │ │ │ └── schemas │ │ │ │ │ └── user.js │ │ │ └── server.js │ │ ├── index.js │ │ ├── config.js │ │ └── package.json │ └── client │ │ ├── .babelrc │ │ ├── scripts │ │ ├── Loader.jsx │ │ ├── Overlay.jsx │ │ ├── FullScreen.jsx │ │ ├── Home.jsx │ │ ├── index.jsx │ │ ├── ChatroomPreview.jsx │ │ ├── socket.js │ │ ├── UserSelection.jsx │ │ ├── MainLayout.jsx │ │ ├── Root.jsx │ │ └── Chatroom.jsx │ │ ├── public │ │ ├── background.jpg │ │ ├── users │ │ │ ├── rick.jpg │ │ │ ├── carol.jpg │ │ │ ├── daryl.jpg │ │ │ └── negan.jpeg │ │ ├── chatrooms │ │ │ ├── hilltop.jpg │ │ │ ├── alexandria.jpg │ │ │ ├── sanctuary.jpg │ │ │ └── terminus.jpg │ │ └── index.html │ │ ├── package.json │ │ └── webpack.config.js ├── images │ ├── image-6-1.webp │ └── image-6-2.webp └── README.md ├── lesson-5 ├── demo │ ├── src │ │ ├── models │ │ │ └── user │ │ │ │ ├── find-user.js │ │ │ │ └── create-user.js │ │ ├── modules │ │ │ ├── app.js │ │ │ └── db │ │ │ │ ├── connect-db.js │ │ │ │ ├── middleware │ │ │ │ └── timestamp.js │ │ │ │ └── schemas │ │ │ │ └── user.js │ │ ├── routes │ │ │ ├── main │ │ │ │ └── main.js │ │ │ ├── user │ │ │ │ ├── get-all-users.js │ │ │ │ ├── delete-user.js │ │ │ │ ├── get-user.js │ │ │ │ ├── create-user.js │ │ │ │ └── update-user.js │ │ │ ├── image │ │ │ │ ├── get-image.js │ │ │ │ └── save-image-multipart.js │ │ │ └── router.js │ │ └── server.js │ ├── index.js │ ├── config.js │ └── package.json └── images │ └── sql-vs-nosql.jpg ├── lesson-8 ├── demo │ └── server │ │ ├── src │ │ ├── domain │ │ │ ├── user │ │ │ │ ├── get.js │ │ │ │ ├── delete.js │ │ │ │ ├── getAll.js │ │ │ │ ├── update.js │ │ │ │ ├── index.js │ │ │ │ └── create.js │ │ │ ├── index.js │ │ │ ├── chat │ │ │ │ ├── index.js │ │ │ │ ├── templates │ │ │ │ │ ├── chatrooms.js │ │ │ │ │ └── users.js │ │ │ │ ├── chatroom-manager.js │ │ │ │ ├── chatroom.js │ │ │ │ ├── client-manager.js │ │ │ │ └── handlers.js │ │ │ └── db │ │ │ │ ├── connect-db.js │ │ │ │ ├── middleware │ │ │ │ └── timestamp.js │ │ │ │ └── schemas │ │ │ │ └── user.js │ │ ├── core │ │ │ ├── input-check │ │ │ │ ├── order.js │ │ │ │ ├── product.js │ │ │ │ ├── index.js │ │ │ │ └── user.js │ │ │ └── index.js │ │ ├── controller │ │ │ ├── app │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── main │ │ │ │ └── index.js │ │ │ ├── users │ │ │ │ ├── get-all-users.js │ │ │ │ ├── delete-user.js │ │ │ │ ├── get-user.js │ │ │ │ ├── create-user.js │ │ │ │ └── update-user.js │ │ │ ├── routes │ │ │ │ └── index.js │ │ │ └── chat │ │ │ │ └── index.js │ │ └── server.js │ │ ├── index.js │ │ ├── config.js │ │ └── package.json ├── images │ ├── onion.jpg │ ├── CleanArchitecture.jpg │ └── onion-architecture.png └── README.md ├── lesson-2 └── demo │ ├── src │ ├── routes │ │ ├── user │ │ │ ├── user-image.json │ │ │ ├── get-user.js │ │ │ └── create-user.js │ │ ├── products │ │ │ ├── create-product.js │ │ │ ├── index.js │ │ │ ├── handle-products-route.js │ │ │ └── send-product.js │ │ ├── main │ │ │ └── main.js │ │ ├── router.js │ │ └── image │ │ │ └── get-image.js │ ├── helpers │ │ └── get-route-handler.js │ └── server.js │ ├── config.js │ ├── data │ └── users │ │ ├── ivan1538002306645.json │ │ └── ivan1538203268673.json │ ├── index.js │ ├── assets │ └── yamaha-v-star-1300-1.jpg │ └── package.json ├── lesson-1 ├── demo │ ├── config.js │ ├── index.js │ ├── assets │ │ └── yamaha-v-star-1300-1.jpg │ ├── src │ │ ├── routes │ │ │ ├── main │ │ │ │ └── main.js │ │ │ ├── router.js │ │ │ ├── motocycle │ │ │ │ └── motocycle.js │ │ │ └── users │ │ │ │ └── sign-up-route.js │ │ └── server.js │ ├── package.json │ └── package-lock.json └── screencast-materials │ ├── node-js-modules │ ├── show-case │ │ ├── services │ │ │ ├── products.js │ │ │ └── user.js │ │ ├── index.js │ │ └── user-consumer.js │ ├── with-modules │ │ ├── index.js │ │ ├── validate-helper.js │ │ ├── database.js │ │ └── controller.js │ └── no-modules │ │ └── all-in-one.js │ ├── http-module │ ├── product-page.html │ ├── products.json │ └── http-server.js │ ├── fs-module │ ├── demo-with-directories.js │ ├── local-database │ │ └── output-products.json │ └── demo-with-files.js │ └── path-module │ └── demo-with-path.js ├── lesson-3 ├── demo │ ├── config.js │ ├── src │ │ ├── modules │ │ │ └── app.js │ │ ├── routes │ │ │ ├── main │ │ │ │ └── main.js │ │ │ ├── user │ │ │ │ ├── get-user.js │ │ │ │ └── create-user.js │ │ │ ├── router.js │ │ │ └── image │ │ │ │ └── save-image-multipart.js │ │ └── server.js │ ├── data │ │ └── users │ │ │ └── bob0.12595476746682865.json │ ├── index.js │ └── package.json ├── img │ ├── 1.png │ ├── 3.png │ ├── 4.png │ └── demo2.js └── README.md ├── .gitignore ├── lesson-4 ├── images │ ├── 1.png │ ├── 12.jpg │ └── maxresdefault.jpg ├── demo │ └── streams │ │ ├── read-stream.js │ │ └── write-stream-transform.js └── README.md ├── lesson-7 ├── images │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── image-6-1.webp │ └── image-6-2.webp ├── JSON-web-token │ ├── app │ │ ├── modules │ │ │ ├── app.js │ │ │ └── check-token.js │ │ ├── routes │ │ │ ├── find-user.js │ │ │ ├── create-user.js │ │ │ └── auth.js │ │ └── models │ │ │ └── user.js │ ├── config.js │ ├── package.json │ └── server.js └── README.md ├── z-demo-10 └── demo │ ├── src │ ├── modules │ │ └── app.js │ ├── routes │ │ ├── main │ │ │ └── main.js │ │ ├── user │ │ │ ├── get-all-users.js │ │ │ ├── delete-user.js │ │ │ ├── get-user.js │ │ │ ├── create-user.js │ │ │ └── update-user.js │ │ ├── image │ │ │ ├── get-image.js │ │ │ └── save-image-multipart.js │ │ └── router.js │ ├── cloud-storage │ │ ├── config.js │ │ ├── index.js │ │ └── service.js │ ├── db │ │ ├── connect-db.js │ │ ├── middleware │ │ │ └── timestamp.js │ │ └── schemas │ │ │ └── user.js │ └── server.js │ ├── data │ └── test-page-tablet-750.jpg │ ├── index.js │ ├── config.js │ └── package.json ├── z-demo-tel-bot-11 └── demo │ ├── config.js │ ├── index.js │ ├── src │ ├── server.js │ └── modules │ │ └── telegram-bot.js │ └── package.json └── lesson-9 └── README.md /lesson-6/demo/server/src/core/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-5/demo/src/models/user/find-user.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/user/get.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/user/get.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/user/user-image.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-5/demo/src/models/user/create-user.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/user/create.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/user/delete.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/user/getAll.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/user/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/user/update.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/user/delete.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/user/getAll.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/user/update.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/core/errors-check/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/core/errors-check/order.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/core/errors-check/product.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/core/input-check/order.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/core/input-check/product.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lesson-1/demo/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 3001 3 | }; -------------------------------------------------------------------------------- /lesson-2/demo/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 8080 3 | }; -------------------------------------------------------------------------------- /lesson-3/demo/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 8080 3 | }; -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/products/create-product.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = () => {}; -------------------------------------------------------------------------------- /lesson-3/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-3/img/1.png -------------------------------------------------------------------------------- /lesson-3/img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-3/img/3.png -------------------------------------------------------------------------------- /lesson-3/img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-3/img/4.png -------------------------------------------------------------------------------- /lesson-6/demo/client/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react" 5 | ] 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .DS_Store 3 | node_modules 4 | ./lesson-10/demo/goit-marketplace-12e07957da8c.json -------------------------------------------------------------------------------- /lesson-4/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-4/images/1.png -------------------------------------------------------------------------------- /lesson-4/images/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-4/images/12.jpg -------------------------------------------------------------------------------- /lesson-7/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-7/images/1.png -------------------------------------------------------------------------------- /lesson-7/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-7/images/2.png -------------------------------------------------------------------------------- /lesson-7/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-7/images/3.png -------------------------------------------------------------------------------- /lesson-3/demo/src/modules/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | module.exports = express(); 4 | -------------------------------------------------------------------------------- /lesson-5/demo/src/modules/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | module.exports = express(); 4 | -------------------------------------------------------------------------------- /lesson-8/images/onion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-8/images/onion.jpg -------------------------------------------------------------------------------- /z-demo-10/demo/src/modules/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | module.exports = express(); 4 | -------------------------------------------------------------------------------- /z-demo-tel-bot-11/demo/config.js: -------------------------------------------------------------------------------- 1 | 2 | const config = { 3 | port: 8080 4 | }; 5 | 6 | module.exports = config; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | module.exports = express(); 4 | -------------------------------------------------------------------------------- /lesson-5/images/sql-vs-nosql.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-5/images/sql-vs-nosql.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/Loader.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default () =>

Loading

4 | -------------------------------------------------------------------------------- /lesson-6/images/image-6-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/images/image-6-1.webp -------------------------------------------------------------------------------- /lesson-6/images/image-6-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/images/image-6-2.webp -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/app/modules/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | module.exports = express(); 4 | -------------------------------------------------------------------------------- /lesson-7/images/image-6-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-7/images/image-6-1.webp -------------------------------------------------------------------------------- /lesson-7/images/image-6-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-7/images/image-6-2.webp -------------------------------------------------------------------------------- /lesson-2/demo/data/users/ivan1538002306645.json: -------------------------------------------------------------------------------- 1 | {"userName":"Ivan","password":"some pass","tel":380635291111,"id":1538002306645} -------------------------------------------------------------------------------- /lesson-2/demo/data/users/ivan1538203268673.json: -------------------------------------------------------------------------------- 1 | {"userName":"Ivan","password":"some pass","tel":380635291111,"id":1538203268673} -------------------------------------------------------------------------------- /lesson-4/images/maxresdefault.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-4/images/maxresdefault.jpg -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/app/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | module.exports = express(); 4 | -------------------------------------------------------------------------------- /lesson-8/images/CleanArchitecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-8/images/CleanArchitecture.jpg -------------------------------------------------------------------------------- /lesson-3/demo/data/users/bob0.12595476746682865.json: -------------------------------------------------------------------------------- 1 | {"userName":"Bob","password":"some pass","tel":380635291111,"id":0.12595476746682865} -------------------------------------------------------------------------------- /lesson-8/demo/server/src/core/index.js: -------------------------------------------------------------------------------- 1 | const inputCheck = require('input-check'); 2 | 3 | export default { 4 | inputCheck 5 | } 6 | -------------------------------------------------------------------------------- /lesson-8/images/onion-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-8/images/onion-architecture.png -------------------------------------------------------------------------------- /lesson-1/demo/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const { port } = require('./config'); 3 | 4 | startServer(port); 5 | -------------------------------------------------------------------------------- /lesson-2/demo/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const { port } = require('./config'); 3 | 4 | startServer(port); 5 | -------------------------------------------------------------------------------- /lesson-3/demo/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const { port } = require('./config'); 3 | 4 | startServer(port); 5 | -------------------------------------------------------------------------------- /lesson-6/demo/client/public/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/background.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/public/users/rick.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/users/rick.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/public/users/carol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/users/carol.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/public/users/daryl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/users/daryl.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/public/users/negan.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/users/negan.jpeg -------------------------------------------------------------------------------- /z-demo-10/demo/data/test-page-tablet-750.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/z-demo-10/demo/data/test-page-tablet-750.jpg -------------------------------------------------------------------------------- /lesson-1/demo/assets/yamaha-v-star-1300-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-1/demo/assets/yamaha-v-star-1300-1.jpg -------------------------------------------------------------------------------- /lesson-2/demo/assets/yamaha-v-star-1300-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-2/demo/assets/yamaha-v-star-1300-1.jpg -------------------------------------------------------------------------------- /z-demo-tel-bot-11/demo/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const { port } = require('./config'); 3 | 4 | startServer(port); 5 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/products/index.js: -------------------------------------------------------------------------------- 1 | const handleProductsRoute = require('./handle-products-route'); 2 | 3 | module.exports = handleProductsRoute; 4 | -------------------------------------------------------------------------------- /lesson-6/demo/client/public/chatrooms/hilltop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/chatrooms/hilltop.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/public/chatrooms/alexandria.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/chatrooms/alexandria.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/public/chatrooms/sanctuary.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/chatrooms/sanctuary.jpg -------------------------------------------------------------------------------- /lesson-6/demo/client/public/chatrooms/terminus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/burnjohn/node-js-course/HEAD/lesson-6/demo/client/public/chatrooms/terminus.jpg -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/show-case/services/products.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getProducts() { 3 | return 'Products service works!'; 4 | } 5 | }; -------------------------------------------------------------------------------- /lesson-3/demo/src/routes/main/main.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | response.set("Content-Type", "text/html"); 3 | response.send("

Привет!

"); 4 | }; 5 | 6 | module.exports = mainRoute; 7 | -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/main/main.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | response.set("Content-Type", "text/html"); 3 | response.send("

Привет!

"); 4 | }; 5 | 6 | module.exports = mainRoute; 7 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/index.js: -------------------------------------------------------------------------------- 1 | const routes = require('./routes'); 2 | const app = require('./app'); 3 | const chat = require('./chat'); 4 | 5 | export default { 6 | routes, 7 | app, 8 | chat 9 | } -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/Overlay.jsx: -------------------------------------------------------------------------------- 1 | import FullScreen from './FullScreen' 2 | 3 | export default FullScreen.extend` 4 | background: ${props => props.background}; 5 | opacity: ${props => props.opacity}; 6 | ` 7 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/main/main.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | response.set("Content-Type", "text/html"); 3 | response.send("

Привет!

"); 4 | }; 5 | 6 | module.exports = mainRoute; 7 | -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/FullScreen.jsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | export default styled.div` 4 | position: absolute; 5 | top: 0; 6 | left: 0; 7 | bottom: 0; 8 | right: 0; 9 | ` 10 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/main/main.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | response.set("Content-Type", "text/html"); 3 | response.send("

Привет!

"); 4 | }; 5 | 6 | module.exports = mainRoute; 7 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/main/main.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | response.set("Content-Type", "text/html"); 3 | response.send("

Привет!

"); 4 | }; 5 | 6 | module.exports = mainRoute; 7 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/main/index.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | response.set("Content-Type", "text/html"); 3 | response.send("

Привет!

"); 4 | }; 5 | 6 | module.exports = mainRoute; 7 | -------------------------------------------------------------------------------- /lesson-5/demo/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const connectToDB = require('./src/modules/db/connect-db'); 3 | const { port, databaseUrl } = require('./config'); 4 | 5 | startServer(port); 6 | connectToDB(databaseUrl); 7 | -------------------------------------------------------------------------------- /lesson-6/demo/server/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const connectToDB = require('./src/db/connect-db'); 3 | const { port, databaseUrl } = require('./config'); 4 | 5 | startServer(port); 6 | connectToDB(databaseUrl); 7 | -------------------------------------------------------------------------------- /lesson-8/demo/server/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const connectToDB = require('./src/db/connect-db'); 3 | const { port, databaseUrl } = require('./config'); 4 | 5 | startServer(port); 6 | connectToDB(databaseUrl); 7 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/core/input-check/index.js: -------------------------------------------------------------------------------- 1 | const order = require('./order'); 2 | const products = require('./products'); 3 | const user = require('./user'); 4 | 5 | export default { 6 | order, 7 | products, 8 | user 9 | } 10 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/main/main.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | response.writeHead(200, {"Content-Type": "text/html"}); 3 | response.write("

Привет!

"); 4 | response.end(); 5 | }; 6 | 7 | module.exports = mainRoute; 8 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/index.js: -------------------------------------------------------------------------------- 1 | const user = require('./user'); 2 | const chat = require('./user'); 3 | 4 | export default { 5 | userAPI: user, 6 | chatAPI: chat, 7 | productAPI: {}, 8 | orderAPI: {}, 9 | authAPI: {} 10 | } 11 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/cloud-storage/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | projectId: 'goit-marketplace', 5 | bucketName: 'goit-marketplace', 6 | keyFilenameSrc: path.join(__dirname, 'goit-marketplace-8a970fbd019c.json'), 7 | }; -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/app/routes/find-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../models/user'); 2 | 3 | const findUser = (req, res) => { 4 | User.find({}, function(err, users) { 5 | res.json(users); 6 | }); 7 | }; 8 | 9 | module.exports = findUser; 10 | -------------------------------------------------------------------------------- /lesson-1/demo/src/routes/main/main.js: -------------------------------------------------------------------------------- 1 | const mainRoute = (request, response) => { 2 | 3 | response.writeHead(200, {"Content-Type": "text/html"}); 4 | response.write("

Hello world 222!

"); 5 | response.end(); 6 | 7 | }; 8 | 9 | module.exports = mainRoute; 10 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/show-case/index.js: -------------------------------------------------------------------------------- 1 | require('./user-consumer'); 2 | const UserService = require('./services/user'); 3 | 4 | const userService = new UserService('batman-123'); 5 | 6 | console.log('From index file: ', userService.getUserFromDB()); 7 | -------------------------------------------------------------------------------- /z-demo-10/demo/index.js: -------------------------------------------------------------------------------- 1 | const startServer = require('./src/server'); 2 | const connectToDB = require('./src/db/connect-db'); 3 | const { port, databaseUrl } = require('./config'); 4 | require('./src/cloud-storage'); 5 | 6 | startServer(port); 7 | connectToDB(databaseUrl); 8 | 9 | -------------------------------------------------------------------------------- /z-demo-tel-bot-11/demo/src/server.js: -------------------------------------------------------------------------------- 1 | const startBot = require('./modules/telegram-bot'); 2 | 3 | const startServer = port => { 4 | startBot(); 5 | 6 | console.log('Server was started at http://localhost:' + port); 7 | }; 8 | 9 | module.exports = startServer; 10 | -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/config.js: -------------------------------------------------------------------------------- 1 | const dbUser = "admin"; 2 | const dbPassword = "qwerty12345"; 3 | 4 | const config = { 5 | secret: 'secret-key', 6 | database: `mongodb://${ dbUser }:${ dbPassword }@ds159020.mlab.com:59020/marketplace-test` 7 | }; 8 | 9 | module.exports = config; -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/chat/index.js: -------------------------------------------------------------------------------- 1 | const clientManager = require('./client-manager'); 2 | const chatRoomManager = require('./chatroom-manager'); 3 | const getChatHandlers = require('./handlers'); 4 | 5 | export default { 6 | clientManager, 7 | chatRoomManager, 8 | getChatHandlers 9 | } -------------------------------------------------------------------------------- /lesson-5/demo/config.js: -------------------------------------------------------------------------------- 1 | const dbUser = "admin"; 2 | const dbPassword = "qwerty12345"; 3 | 4 | const config = { 5 | port: 8080, 6 | dbUser, 7 | dbPassword, 8 | databaseUrl: `mongodb://${ dbUser }:${ dbPassword }@ds159020.mlab.com:59020/marketplace-test` 9 | }; 10 | 11 | module.exports = config; -------------------------------------------------------------------------------- /z-demo-10/demo/config.js: -------------------------------------------------------------------------------- 1 | const dbUser = "admin"; 2 | const dbPassword = "qwerty12345"; 3 | 4 | const config = { 5 | port: 8080, 6 | dbUser, 7 | dbPassword, 8 | databaseUrl: `mongodb://${ dbUser }:${ dbPassword }@ds159020.mlab.com:59020/marketplace-test` 9 | }; 10 | 11 | module.exports = config; -------------------------------------------------------------------------------- /lesson-6/demo/server/config.js: -------------------------------------------------------------------------------- 1 | const dbUser = "admin"; 2 | const dbPassword = "qwerty12345"; 3 | 4 | const config = { 5 | port: 8080, 6 | dbUser, 7 | dbPassword, 8 | databaseUrl: `mongodb://${ dbUser }:${ dbPassword }@ds159020.mlab.com:59020/marketplace-test` 9 | }; 10 | 11 | module.exports = config; -------------------------------------------------------------------------------- /lesson-8/demo/server/config.js: -------------------------------------------------------------------------------- 1 | const dbUser = "admin"; 2 | const dbPassword = "qwerty12345"; 3 | 4 | const config = { 5 | port: 8080, 6 | dbUser, 7 | dbPassword, 8 | databaseUrl: `mongodb://${ dbUser }:${ dbPassword }@ds159020.mlab.com:59020/marketplace-test` 9 | }; 10 | 11 | module.exports = config; -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/with-modules/index.js: -------------------------------------------------------------------------------- 1 | const orderController = require('./controller'); 2 | 3 | orderController.saveOrder({ 4 | items: [ 5 | { name: 'pizza', count: 2 }, 6 | { name: 'beer', count: 1 }, 7 | ], 8 | time: 1555242804290, 9 | userId: '123' 10 | }); 11 | 12 | console.log(express); 13 | 14 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/with-modules/validate-helper.js: -------------------------------------------------------------------------------- 1 | 2 | const getOrdersMissingFields = (order) => { 3 | if (!order.items) { 4 | return 'items are missing'; 5 | } 6 | 7 | console.log('getOrdersMissingFields works'); 8 | 9 | return null; 10 | }; 11 | 12 | module.exports = { 13 | getOrdersMissingFields 14 | }; 15 | -------------------------------------------------------------------------------- /lesson-1/demo/src/routes/router.js: -------------------------------------------------------------------------------- 1 | const mainRoute = require('./main/main'); 2 | const motocycleRoute = require('./motocycle/motocycle'); 3 | const signUpRoute = require('./users/sign-up-route'); 4 | 5 | const router = { 6 | '/signup': signUpRoute, 7 | '/motocycle': motocycleRoute, 8 | default: mainRoute 9 | }; 10 | 11 | module.exports = router; 12 | -------------------------------------------------------------------------------- /lesson-1/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.7.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "node --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "morgan": "^1.9.1", 14 | "nodemon": "^1.18.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/http-module/product-page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 |

Hello, I'm the product page!

11 | 12 | 13 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/user/index.js: -------------------------------------------------------------------------------- 1 | const getAll = require('getAll'); 2 | const get = require('get'); 3 | const deleteUser = require('delete'); 4 | const update = require('update'); 5 | const create = require('create'); 6 | 7 | export default { 8 | getAllUser: getAll, 9 | getUser: get, 10 | deleteUser, 11 | updateUser: update, 12 | createUser: create, 13 | } 14 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/db/connect-db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectToDB = (dbUrl) => { 4 | mongoose.connect(dbUrl, { useNewUrlParser: true }) 5 | .then(() => { 6 | console.log('Database connection successful') 7 | }) 8 | .catch(err => { 9 | console.error('Database connection error') 10 | }) 11 | }; 12 | 13 | module.exports = connectToDB; 14 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/show-case/user-consumer.js: -------------------------------------------------------------------------------- 1 | const UserService = require('./services/user'); 2 | 3 | const userService = new UserService('user-123'); 4 | 5 | console.log('From user consumer file: ', userService.getUserFromDB()); 6 | 7 | const newUser = { 8 | name: 'BILL', 9 | email: 'bill@gmail.com', 10 | age: 22, 11 | }; 12 | 13 | userService.saveNewUser(newUser); 14 | -------------------------------------------------------------------------------- /lesson-5/demo/src/modules/db/connect-db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectToDB = (dbUrl) => { 4 | mongoose.connect(dbUrl, { useNewUrlParser: true }) 5 | .then(() => { 6 | console.log('Database connection successful') 7 | }) 8 | .catch(err => { 9 | console.error('Database connection error') 10 | }) 11 | }; 12 | 13 | module.exports = connectToDB; 14 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/db/connect-db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectToDB = (dbUrl) => { 4 | mongoose.connect(dbUrl, { useNewUrlParser: true }) 5 | .then(() => { 6 | console.log('Database connection successful') 7 | }) 8 | .catch(err => { 9 | console.error('Database connection error') 10 | }) 11 | }; 12 | 13 | module.exports = connectToDB; 14 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/db/connect-db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectToDB = (dbUrl) => { 4 | mongoose.connect(dbUrl, { useNewUrlParser: true }) 5 | .then(() => { 6 | console.log('Database connection successful') 7 | }) 8 | .catch(err => { 9 | console.error('Database connection error') 10 | }) 11 | }; 12 | 13 | module.exports = connectToDB; 14 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/db/connect-db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectToDB = (dbUrl) => { 4 | mongoose.connect(dbUrl, { useNewUrlParser: true }) 5 | .then(() => { 6 | console.log('Database connection successful') 7 | }) 8 | .catch(err => { 9 | console.error('Database connection error') 10 | }) 11 | }; 12 | 13 | module.exports = connectToDB; 14 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/with-modules/database.js: -------------------------------------------------------------------------------- 1 | 2 | const ordersStorage = {}; 3 | 4 | const dataBase = {}; 5 | 6 | dataBase.saveOrder = (order, userId) =>{ 7 | ordersStorage[userId] = order; 8 | 9 | console.log('dataBase.saveOrder: ', ordersStorage); 10 | }; 11 | 12 | dataBase.getOrder = (userId) => { 13 | return ordersStorage[userId]; 14 | }; 15 | 16 | module.exports = dataBase; 17 | -------------------------------------------------------------------------------- /lesson-6/demo/client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TWD Chat 5 | 6 | 11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/chat/templates/chatrooms.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: 'Terminus', 4 | image: 'chatrooms/terminus.jpg' 5 | }, 6 | { 7 | name: 'Alexandria', 8 | image: 'chatrooms/alexandria.jpg' 9 | }, 10 | { 11 | name: 'Sanctuary', 12 | image: 'chatrooms/sanctuary.jpg' 13 | }, 14 | { 15 | name: 'Hilltop', 16 | image: 'chatrooms/hilltop.jpg' 17 | } 18 | ]; -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/chat/templates/chatrooms.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: 'Terminus', 4 | image: 'chatrooms/terminus.jpg' 5 | }, 6 | { 7 | name: 'Alexandria', 8 | image: 'chatrooms/alexandria.jpg' 9 | }, 10 | { 11 | name: 'Sanctuary', 12 | image: 'chatrooms/sanctuary.jpg' 13 | }, 14 | { 15 | name: 'Hilltop', 16 | image: 'chatrooms/hilltop.jpg' 17 | } 18 | ]; -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/app/models/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { Schema } = mongoose; 3 | 4 | const userSchema = new Schema({ 5 | firstName: String, 6 | lastName: String, 7 | telephone: String, 8 | nickName: String, 9 | location: String, 10 | email: String, 11 | password: String 12 | }); 13 | 14 | const User = mongoose.model('User', userSchema); 15 | 16 | module.exports = User; 17 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/user/get-all-users.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getAllUser = (request, response) => { 4 | const sendResponse = (user) => { 5 | response.status(200); 6 | response.json(user); 7 | }; 8 | 9 | User 10 | .find() 11 | .then(sendResponse) 12 | .catch(err => { 13 | console.error(err) 14 | }); 15 | }; 16 | 17 | module.exports = getAllUser; 18 | -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/user/get-all-users.js: -------------------------------------------------------------------------------- 1 | const User = require('../../modules/db/schemas/user'); 2 | 3 | const getAllUser = (request, response) => { 4 | const sendResponse = (user) => { 5 | response.status(200); 6 | response.json(user); 7 | }; 8 | 9 | User 10 | .find() 11 | .then(sendResponse) 12 | .catch(err => { 13 | console.error(err) 14 | }); 15 | }; 16 | 17 | module.exports = getAllUser; 18 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/user/get-all-users.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getAllUser = (request, response) => { 4 | const sendResponse = (user) => { 5 | response.status(200); 6 | response.json(user); 7 | }; 8 | 9 | User 10 | .find() 11 | .then(sendResponse) 12 | .catch(err => { 13 | console.error(err) 14 | }); 15 | }; 16 | 17 | module.exports = getAllUser; 18 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/users/get-all-users.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getAllUser = (request, response) => { 4 | const sendResponse = (user) => { 5 | response.status(200); 6 | response.json(user); 7 | }; 8 | 9 | User 10 | .find() 11 | .then(sendResponse) 12 | .catch(err => { 13 | console.error(err) 14 | }); 15 | }; 16 | 17 | module.exports = getAllUser; 18 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/users/get-all-users.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/users'); 2 | 3 | const getAllUser = (request, response) => { 4 | const sendResponse = (user) => { 5 | response.status(200); 6 | response.json(user); 7 | }; 8 | 9 | User 10 | .find() 11 | .then(sendResponse) 12 | .catch(err => { 13 | console.error(err) 14 | }); 15 | }; 16 | 17 | module.exports = getAllUser; 18 | -------------------------------------------------------------------------------- /lesson-3/demo/src/routes/user/get-user.js: -------------------------------------------------------------------------------- 1 | 2 | const getUserFromDb = (id) => { 3 | 4 | const src = path.resolve(usersFolder, fileName + '.json'); 5 | 6 | return readFileSync(src); 7 | }; 8 | 9 | const getUser = (request, response) => { 10 | const id = request.params.userId; 11 | 12 | response.set("Content-Type", "application/json"); 13 | 14 | response.status(200); 15 | response.json({ user: getUserFromDb(id) }); 16 | }; 17 | 18 | module.exports = getUser; 19 | -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import ChatroomPreview from './ChatroomPreview' 4 | 5 | export default ({ 6 | chatrooms, 7 | onEnterChatroom 8 | }) => ( 9 |
10 | { 11 | chatrooms.map(chatroom => ( 12 | onEnterChatroom(chatroom.name)} 16 | /> 17 | )) 18 | } 19 |
20 | ) 21 | -------------------------------------------------------------------------------- /lesson-2/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "nodemon --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "body-parser": "^1.18.3", 14 | "connect-multiparty": "^2.2.0", 15 | "form-data": "^2.3.2", 16 | "morgan": "^1.9.1", 17 | "nodemon": "^1.18.4" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/user/delete-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | 6 | const sendResponse = (user) => { 7 | response.status(200); 8 | response.json(user); 9 | }; 10 | 11 | User 12 | .findById(id) 13 | .remove() 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/router.js: -------------------------------------------------------------------------------- 1 | const mainRoute = require('./main/main'); 2 | const imageRoute = require('./image/get-image'); 3 | const getUser = require('./user/get-user'); 4 | const handleProductsRoute = require('./products'); 5 | 6 | const router = { 7 | '/me': mainRoute, 8 | '/image': imageRoute, 9 | '/users': getUser, 10 | '/products': handleProductsRoute, 11 | '/products/add-order': handleProductsRoute, 12 | default: mainRoute 13 | }; 14 | 15 | module.exports = router; 16 | -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/user/delete-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../modules/db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | 6 | const sendResponse = (user) => { 7 | response.status(200); 8 | response.json(user); 9 | }; 10 | 11 | User 12 | .findById(id) 13 | .remove() 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/user/delete-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | 6 | const sendResponse = (user) => { 7 | response.status(200); 8 | response.json(user); 9 | }; 10 | 11 | User 12 | .findById(id) 13 | .remove() 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/users/delete-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | 6 | const sendResponse = (user) => { 7 | response.status(200); 8 | response.json(user); 9 | }; 10 | 11 | User 12 | .findById(id) 13 | .remove() 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/users/delete-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/users'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | 6 | const sendResponse = (user) => { 7 | response.status(200); 8 | response.json(user); 9 | }; 10 | 11 | User 12 | .findById(id) 13 | .remove() 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/products/handle-products-route.js: -------------------------------------------------------------------------------- 1 | const sendProduct = require('./send-product'); 2 | const createProduct = require('./create-product'); 3 | 4 | const handleProductsRoute = (request, response) => { 5 | const reqMethod = request.method; 6 | 7 | if (reqMethod === 'GET') { 8 | sendProduct(request, response); 9 | return; 10 | } 11 | 12 | if (reqMethod === 'POST') { 13 | createProduct(request, response); 14 | } 15 | }; 16 | 17 | module.exports = handleProductsRoute; -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import Root from './Root'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root') 9 | ) 10 | 11 | if (module.hot) { 12 | module.hot.accept('./Root', () => { 13 | // eslint-disable-next-line 14 | const NextRoot = require('./Root').default 15 | ReactDOM.render( 16 | , 17 | document.getElementById('root') 18 | ) 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/db/middleware/timestamp.js: -------------------------------------------------------------------------------- 1 | const setTimestamp = (schema) => { 2 | // Добавляем к схеме 2 поля 3 | schema.add({ 4 | createdAt: Date, 5 | updatedAt: Date 6 | }); 7 | 8 | // Создаем хук на pre-save 9 | schema.pre('save', (next) => { 10 | const now = Date.now(); 11 | 12 | this.updatedAt = now; 13 | 14 | if (!this.createdAt) { 15 | this.createdAt = now 16 | } 17 | 18 | next() 19 | }); 20 | }; 21 | 22 | module.exports = setTimestamp; 23 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/db/middleware/timestamp.js: -------------------------------------------------------------------------------- 1 | const setTimestamp = (schema) => { 2 | // Добавляем к схеме 2 поля 3 | schema.add({ 4 | createdAt: Date, 5 | updatedAt: Date 6 | }); 7 | 8 | // Создаем хук на pre-save 9 | schema.pre('save', function(next) { 10 | const now = Date.now(); 11 | 12 | this.updatedAt = now; 13 | 14 | if (!this.createdAt) { 15 | this.createdAt = now 16 | } 17 | 18 | next() 19 | }); 20 | }; 21 | 22 | module.exports = setTimestamp; 23 | -------------------------------------------------------------------------------- /lesson-5/demo/src/modules/db/middleware/timestamp.js: -------------------------------------------------------------------------------- 1 | const setTimestamp = (schema) => { 2 | // Добавляем к схеме 2 поля 3 | schema.add({ 4 | createdAt: Date, 5 | updatedAt: Date 6 | }); 7 | 8 | // Создаем хук на pre-save 9 | schema.pre('save', function(next) { 10 | const now = Date.now(); 11 | 12 | this.updatedAt = now; 13 | 14 | if (!this.createdAt) { 15 | this.createdAt = now 16 | } 17 | 18 | next() 19 | }); 20 | }; 21 | 22 | module.exports = setTimestamp; 23 | -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/user/get-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../modules/db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | 5 | const id = request.params.id; 6 | 7 | const sendResponse = (user) => { 8 | response.status(200); 9 | response.json(user); 10 | }; 11 | 12 | const findUser = User.findById(id); 13 | 14 | findUser 15 | .then(sendResponse) 16 | .catch(err => { 17 | console.error(err) 18 | }); 19 | }; 20 | 21 | module.exports = getUser; 22 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/db/middleware/timestamp.js: -------------------------------------------------------------------------------- 1 | const setTimestamp = (schema) => { 2 | // Добавляем к схеме 2 поля 3 | schema.add({ 4 | createdAt: Date, 5 | updatedAt: Date 6 | }); 7 | 8 | // Создаем хук на pre-save 9 | schema.pre('save', (next) => { 10 | const now = Date.now(); 11 | 12 | this.updatedAt = now; 13 | 14 | if (!this.createdAt) { 15 | this.createdAt = now 16 | } 17 | 18 | next() 19 | }); 20 | }; 21 | 22 | module.exports = setTimestamp; 23 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/db/middleware/timestamp.js: -------------------------------------------------------------------------------- 1 | const setTimestamp = (schema) => { 2 | // Добавляем к схеме 2 поля 3 | schema.add({ 4 | createdAt: Date, 5 | updatedAt: Date 6 | }); 7 | 8 | // Создаем хук на pre-save 9 | schema.pre('save', (next) => { 10 | const now = Date.now(); 11 | 12 | this.updatedAt = now; 13 | 14 | if (!this.createdAt) { 15 | this.createdAt = now 16 | } 17 | 18 | next() 19 | }); 20 | }; 21 | 22 | module.exports = setTimestamp; 23 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/db/schemas/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { Schema } = mongoose; 3 | const timestamp = require('../middleware/timestamp'); 4 | 5 | const userSchema = new Schema({ 6 | firstName: String, 7 | lastName: String, 8 | telephone: String, 9 | nickName: String, 10 | location: String, 11 | password: String, 12 | email: String 13 | }); 14 | 15 | userSchema.plugin(timestamp); 16 | 17 | const User = mongoose.model('User', userSchema); 18 | 19 | module.exports = User; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/core/errors-check/user.js: -------------------------------------------------------------------------------- 1 | 2 | const NO_PASSWORD_MESSAGE = 'No user password'; 3 | const NO_NAME_MESSAGE = 'No user name'; 4 | 5 | const userErrorsChecker = (userInput) => { 6 | const errorMessageList = []; 7 | 8 | if (!userInput.password) { 9 | errorMessageList.push(NO_PASSWORD_MESSAGE) 10 | } 11 | 12 | if (!userInput.name) { 13 | errorMessageList.push(NO_NAME_MESSAGE) 14 | } 15 | 16 | return errorMessageList; 17 | }; 18 | 19 | export default userErrorsChecker; 20 | -------------------------------------------------------------------------------- /lesson-5/demo/src/modules/db/schemas/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { Schema } = mongoose; 3 | const timestamp = require('../middleware/timestamp'); 4 | 5 | const userSchema = new Schema({ 6 | firstName: String, 7 | lastName: String, 8 | telephone: String, 9 | nickName: String, 10 | location: String, 11 | password: String, 12 | email: String 13 | }); 14 | 15 | userSchema.plugin(timestamp); 16 | 17 | const User = mongoose.model('User', userSchema); 18 | 19 | module.exports = User; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/db/schemas/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { Schema } = mongoose; 3 | const timestamp = require('../middleware/timestamp'); 4 | 5 | const userSchema = new Schema({ 6 | firstName: String, 7 | lastName: String, 8 | telephone: String, 9 | nickName: String, 10 | location: String, 11 | password: String, 12 | email: String 13 | }); 14 | 15 | // userSchema.plugin(timestamp); 16 | 17 | const User = mongoose.model('User', userSchema); 18 | 19 | module.exports = User; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/domain/db/schemas/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { Schema } = mongoose; 3 | const timestamp = require('../middleware/timestamp'); 4 | 5 | const userSchema = new Schema({ 6 | firstName: String, 7 | lastName: String, 8 | telephone: String, 9 | nickName: String, 10 | location: String, 11 | password: String, 12 | email: String 13 | }); 14 | 15 | // userSchema.plugin(timestamp); 16 | 17 | const User = mongoose.model('User', userSchema); 18 | 19 | module.exports = User; -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/db/schemas/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { Schema } = mongoose; 3 | const timestamp = require('../middleware/timestamp'); 4 | 5 | const userSchema = new Schema({ 6 | firstName: String, 7 | lastName: String, 8 | telephone: String, 9 | nickName: String, 10 | location: String, 11 | password: String, 12 | email: String 13 | }); 14 | 15 | // userSchema.plugin(timestamp); 16 | 17 | const User = mongoose.model('User', userSchema); 18 | 19 | module.exports = User; -------------------------------------------------------------------------------- /z-demo-tel-bot-11/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "nodemon --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt": "^3.0.2", 14 | "body-parser": "^1.18.3", 15 | "express": "^4.16.3", 16 | "morgan": "^1.9.1", 17 | "node-telegram-bot-api": "^0.30.0", 18 | "nodemon": "^1.18.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lesson-3/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "nodemon --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt": "^3.0.0", 14 | "body-parser": "^1.18.3", 15 | "express": "^4.16.3", 16 | "jsonwebtoken": "^8.3.0", 17 | "morgan": "^1.9.1", 18 | "multer": "^1.4.0", 19 | "nodemon": "^1.18.4" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lesson-5/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "nodemon --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt": "^3.0.0", 14 | "body-parser": "^1.18.3", 15 | "express": "^4.16.3", 16 | "morgan": "^1.9.1", 17 | "multer": "^1.4.0", 18 | "nodemon": "^1.18.4", 19 | "mongoose": "^5.2.14" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/image/get-image.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const motocycleRoute = (request, response) => { 5 | const filePath = path.join(__dirname, '../../../', 'assets', 'yamaha-v-star-1300-1.jpg'); 6 | const image = fs.statSync(filePath); 7 | 8 | response 9 | .set('Content-Type', 'image/jpeg') 10 | .set('Content-Length', image.size); 11 | 12 | const readStream = fs.createReadStream(filePath); 13 | readStream.pipe(response); 14 | }; 15 | 16 | module.exports = motocycleRoute; 17 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/image/get-image.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const motocycleRoute = (request, response) => { 5 | const filePath = path.join(__dirname, '../../../', 'assets', 'yamaha-v-star-1300-1.jpg'); 6 | const image = fs.statSync(filePath); 7 | 8 | response 9 | .set('Content-Type', 'image/jpeg') 10 | .set('Content-Length', image.size); 11 | 12 | const readStream = fs.createReadStream(filePath); 13 | readStream.pipe(response); 14 | }; 15 | 16 | module.exports = motocycleRoute; 17 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/image/get-image.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const motocycleRoute = (request, response) => { 5 | const filePath = path.join(__dirname, '../../../', 'assets', 'yamaha-v-star-1300-1.jpg'); 6 | const image = fs.statSync(filePath); 7 | 8 | response 9 | .set('Content-Type', 'image/jpeg') 10 | .set('Content-Length', image.size); 11 | 12 | const readStream = fs.createReadStream(filePath); 13 | readStream.pipe(response); 14 | }; 15 | 16 | module.exports = motocycleRoute; 17 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/image/get-image.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const motocycleRoute = (request, response) => { 5 | const filePath = path.join(__dirname, '../../../', 'assets', 'yamaha-v-star-1300-1.jpg'); 6 | const image = fs.statSync(filePath); 7 | 8 | response 9 | .set('Content-Type', 'image/jpeg') 10 | .set('Content-Length', image.size); 11 | 12 | const readStream = fs.createReadStream(filePath); 13 | readStream.pipe(response); 14 | }; 15 | 16 | module.exports = motocycleRoute; 17 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/image/get-image.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const motocycleRoute = (request, response) => { 5 | const filePath = path.join(__dirname, '../../../', 'assets', 'yamaha-v-star-1300-1.jpg'); 6 | const image = fs.statSync(filePath); 7 | 8 | response.writeHead(200, { 9 | 'Content-Type': 'image/jpeg', 10 | 'Content-Length': image.size 11 | }); 12 | 13 | const readStream = fs.createReadStream(filePath); 14 | readStream.pipe(response); 15 | }; 16 | 17 | module.exports = motocycleRoute; 18 | -------------------------------------------------------------------------------- /lesson-6/demo/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "nodemon --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt": "^3.0.0", 14 | "body-parser": "^1.18.3", 15 | "express": "^4.16.3", 16 | "mongoose": "^5.2.14", 17 | "morgan": "^1.9.1", 18 | "multer": "^1.4.0", 19 | "nodemon": "^1.18.4", 20 | "socket.io": "^2.1.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lesson-8/demo/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "nodemon --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt": "^3.0.0", 14 | "body-parser": "^1.18.3", 15 | "express": "^4.16.3", 16 | "mongoose": "^5.2.14", 17 | "morgan": "^1.9.1", 18 | "multer": "^1.4.0", 19 | "nodemon": "^1.18.4", 20 | "socket.io": "^2.1.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lesson-1/demo/src/routes/motocycle/motocycle.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const motocycleRoute = (request, response) => { 5 | const filePath = path.join(__dirname, '../../../', 'assets', 'yamaha-v-star-1300-1.jpg'); 6 | const image = fs.statSync(filePath); 7 | 8 | response.writeHead(200, { 9 | 'Content-Type': 'image/jpeg', 10 | 'Content-Length': image.size 11 | }); 12 | 13 | const readStream = fs.createReadStream(filePath); 14 | 15 | readStream.pipe(response); 16 | }; 17 | 18 | module.exports = motocycleRoute; 19 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/fs-module/demo-with-directories.js: -------------------------------------------------------------------------------- 1 | // fs.readdir - для получения информации о папке https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback 2 | // fs.mkdir - для создания папки https://nodejs.org/api/fs.html#fs_fs_mkdir_path_options_callback 3 | // fs.stat - для получения информации о файле/папке https://nodejs.org/docs/latest/api/fs.html#fs_fs_stat_path_options_callback 4 | 5 | const fs = require('fs'); 6 | 7 | const files = fs.readdirSync(__dirname); 8 | 9 | const fileData = fs.statSync(files[0]); 10 | 11 | console.log(fileData.size); -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/with-modules/controller.js: -------------------------------------------------------------------------------- 1 | const helpers = require('./validate-helper'); 2 | const dataBase = require('./database'); 3 | 4 | const orderController = {}; 5 | 6 | orderController.saveOrder = (order) => { 7 | if (helpers.getOrdersMissingFields(order)) { 8 | return; 9 | } 10 | 11 | console.log('SaveOrder in controller'); 12 | 13 | dataBase.saveOrder(order, order.userId); 14 | }; 15 | 16 | orderController.getUserOrder = (userId) => { 17 | dataBase.getOrder(userId); 18 | }; 19 | 20 | module.exports = orderController; 21 | -------------------------------------------------------------------------------- /z-demo-10/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "debug": "nodemon --inspect index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@google-cloud/storage": "^2.3.1", 14 | "bcrypt": "3.0.2", 15 | "body-parser": "^1.18.3", 16 | "express": "^4.16.3", 17 | "mongoose": "^5.2.14", 18 | "morgan": "^1.9.1", 19 | "multer": "^1.4.0", 20 | "nodemon": "^1.18.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/user/get-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | const sendResponse = ([user, product]) => { 6 | response.status(200); 7 | response.json(user); 8 | }; 9 | 10 | const findUser = User.findById(id); 11 | const findProduct = Product.findById(id); 12 | 13 | Promise.all([findUser, findProduct]) 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/user/get-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | const sendResponse = ([user, product]) => { 6 | response.status(200); 7 | response.json(user); 8 | }; 9 | 10 | const findUser = User.findById(id); 11 | const findProduct = Product.findById(id); 12 | 13 | Promise.all([findUser, findProduct]) 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/user/get-user.js: -------------------------------------------------------------------------------- 1 | const url = require('url'); 2 | 3 | const getId = url => { 4 | const lastIndex = url.lastIndexOf('/'); 5 | 6 | if (lastIndex !== -1) { 7 | return url.slice(lastIndex +1); 8 | } 9 | }; 10 | 11 | const getUser = (request, response) => { 12 | const parsedUrl = url.parse(request.url); 13 | const id = getId(parsedUrl.path); 14 | 15 | 16 | 17 | response.writeHead(200, {"Content-Type": "application/json"}); 18 | response.write(JSON.stringify({ userId: id })); 19 | response.end(); 20 | }; 21 | 22 | module.exports = getUser; 23 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/users/get-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | const sendResponse = ([user, product]) => { 6 | response.status(200); 7 | response.json(user); 8 | }; 9 | 10 | const findUser = User.findById(id); 11 | const findProduct = Product.findById(id); 12 | 13 | Promise.all([findUser, findProduct]) 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/users/get-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/users'); 2 | 3 | const getUser = (request, response) => { 4 | const id = request.params.id; 5 | const sendResponse = ([user, product]) => { 6 | response.status(200); 7 | response.json(user); 8 | }; 9 | 10 | const findUser = User.findById(id); 11 | const findProduct = Product.findById(id); 12 | 13 | Promise.all([findUser, findProduct]) 14 | .then(sendResponse) 15 | .catch(err => { 16 | console.error(err) 17 | }); 18 | }; 19 | 20 | module.exports = getUser; 21 | -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/products/send-product.js: -------------------------------------------------------------------------------- 1 | const url = require('url'); 2 | 3 | const getId = url => { 4 | const lastIndex = url.lastIndexOf('/'); 5 | 6 | if (lastIndex !== -1) { 7 | return url.slice(lastIndex +1); 8 | } 9 | }; 10 | 11 | const getProducts = (request, response) => { 12 | const parsedUrl = url.parse(request.url); 13 | const id = getId(parsedUrl.path); 14 | 15 | response.writeHead(200, {"Content-Type": "application/json"}); 16 | response.write(JSON.stringify({ productid: id })); 17 | response.end(); 18 | }; 19 | 20 | module.exports = getProducts; 21 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/users/create-user.js: -------------------------------------------------------------------------------- 1 | const domain = require('../../domain'); 2 | 3 | const createUser = (request, response) => { 4 | const user = request.body; 5 | 6 | const sendResponse = (user) => { 7 | response.json({ 8 | status: 'success', 9 | user 10 | }); 11 | }; 12 | 13 | const sendError = () => { 14 | response.status(400); 15 | response.json({ 16 | error: 'users was not saved' 17 | }); 18 | }; 19 | 20 | domain.userAPI.createUser(user) 21 | .then(sendResponse) 22 | .catch(sendError) 23 | }; 24 | 25 | module.exports = createUser; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/users/create-user.js: -------------------------------------------------------------------------------- 1 | const domain = require('../../domain'); 2 | 3 | const createUser = (request, response) => { 4 | const user = request.body; 5 | 6 | const sendResponse = (user) => { 7 | 8 | 9 | response.json({ 10 | status: 'success', 11 | user 12 | }); 13 | }; 14 | 15 | const sendError = () => { 16 | response.status(400); 17 | response.json({ 18 | error: 'user was not saved' 19 | }); 20 | }; 21 | 22 | domain.userAPI.createUser(user) 23 | .then(sendResponse) 24 | .catch(sendError) 25 | 26 | }; 27 | 28 | module.exports = createUser; -------------------------------------------------------------------------------- /z-demo-10/demo/src/cloud-storage/index.js: -------------------------------------------------------------------------------- 1 | const { Storage } = require('@google-cloud/storage'); 2 | const { keyFilenameSrc, bucketName } = require('./config'); 3 | 4 | const storage = new Storage({ 5 | projectId: bucketName, 6 | keyFilename: keyFilenameSrc 7 | }); 8 | 9 | let bucket = null; 10 | 11 | const createBucket = () => 12 | bucket.create() 13 | .then(() => { 14 | console.log('Bucket was successfully created') 15 | }).catch(error => { 16 | console.log('Error in creating bucket', error); 17 | }); 18 | 19 | bucket = storage.bucket(bucketName) || createBucket(); 20 | 21 | module.exports = bucket; 22 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/core/input-check/user.js: -------------------------------------------------------------------------------- 1 | 2 | const NO_PASSWORD_MESSAGE = 'No users password'; 3 | const NO_NAME_MESSAGE = 'No users name'; 4 | const NO_USER_INPUT = 'No user input'; 5 | 6 | const userErrorsChecker = (userInput) => { 7 | const errorMessageList = []; 8 | 9 | if (!userInput) { 10 | errorMessageList.push(NO_USER_INPUT); 11 | return errorMessageList; 12 | } 13 | 14 | if (!userInput.password) { 15 | errorMessageList.push(NO_PASSWORD_MESSAGE) 16 | } 17 | 18 | if (!userInput.name) { 19 | errorMessageList.push(NO_NAME_MESSAGE) 20 | } 21 | 22 | return errorMessageList; 23 | }; 24 | 25 | export default userErrorsChecker; 26 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/show-case/services/user.js: -------------------------------------------------------------------------------- 1 | const productsService = (() => {})(); 2 | 3 | const userService = ((products) => { 4 | const DEFAULT_USER = { 5 | name: 'Bob', 6 | email: 'bob@gmail.com', 7 | age: 40, 8 | }; 9 | 10 | products.getProducts(); 11 | 12 | class UserService { 13 | constructor(userId) { 14 | this.user = { 15 | ...DEFAULT_USER, 16 | userId 17 | }; 18 | } 19 | 20 | saveNewUser(newUser) { 21 | this.user = newUser; 22 | } 23 | 24 | getUserFromDB() { 25 | return this.user; 26 | } 27 | } 28 | 29 | return UserService; 30 | })(productsService); 31 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/chat/templates/users.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: 'Rick', 4 | lastName: 'Grimes', 5 | statusText: 'I am the leader!', 6 | image: 'users/rick.jpg' 7 | }, 8 | { 9 | name: 'Daryl', 10 | lastName: 'Dixon', 11 | statusText: 'I like smashing Walkers.', 12 | image: 'users/daryl.jpg' 13 | }, 14 | { 15 | name: 'Carol', 16 | lastName: 'Peletier', 17 | statusText: 'Don\'t mess with me!', 18 | image: 'users/carol.jpg' 19 | }, 20 | { 21 | name: 'Negan', 22 | lastName: '', 23 | statusText: 'In a relationship with Lucille.', 24 | image: 'users/negan.jpeg' 25 | } 26 | ] 27 | 28 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/chat/templates/users.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: 'Rick', 4 | lastName: 'Grimes', 5 | statusText: 'I am the leader!', 6 | image: 'users/rick.jpg' 7 | }, 8 | { 9 | name: 'Daryl', 10 | lastName: 'Dixon', 11 | statusText: 'I like smashing Walkers.', 12 | image: 'users/daryl.jpg' 13 | }, 14 | { 15 | name: 'Carol', 16 | lastName: 'Peletier', 17 | statusText: 'Don\'t mess with me!', 18 | image: 'users/carol.jpg' 19 | }, 20 | { 21 | name: 'Negan', 22 | lastName: '', 23 | statusText: 'In a relationship with Lucille.', 24 | image: 'users/negan.jpeg' 25 | } 26 | ] 27 | 28 | -------------------------------------------------------------------------------- /lesson-1/demo/src/server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const url = require('url'); 3 | 4 | const morgan = require('morgan'); 5 | const router = require('./routes/router'); 6 | 7 | const logger = morgan('combined'); 8 | 9 | const startServer = port => { 10 | 11 | const server = http.createServer((request, response) => { 12 | 13 | // Get route from the request 14 | const parsedUrl = url.parse(request.url); 15 | 16 | // Get router function 17 | const func = router[parsedUrl.pathname] || router.default; 18 | 19 | logger(request, response, () => func(request, response)); 20 | }); 21 | 22 | server.listen(port); 23 | }; 24 | 25 | module.exports = startServer; 26 | -------------------------------------------------------------------------------- /lesson-5/demo/src/server.js: -------------------------------------------------------------------------------- 1 | const bodyParser = require('body-parser'); 2 | const app = require('./modules/app'); 3 | const morgan = require('morgan'); 4 | const router = require('./routes/router'); 5 | 6 | const errorHandler = (err, req, res, next) => { 7 | console.error(err.stack); 8 | 9 | res.json(404).send('No such page'); 10 | }; 11 | 12 | const startServer = port => { 13 | app 14 | .use(bodyParser.urlencoded({extended: false})) 15 | .use(bodyParser.json()) 16 | .use(morgan('dev')) 17 | .use('/', router) 18 | .use(errorHandler); 19 | 20 | app.listen(port); 21 | 22 | console.log('Server was started at http://localhost:' + port); 23 | }; 24 | 25 | module.exports = startServer; 26 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/server.js: -------------------------------------------------------------------------------- 1 | const bodyParser = require('body-parser'); 2 | const app = require('./modules/app'); 3 | const morgan = require('morgan'); 4 | const router = require('./routes/router'); 5 | 6 | const errorHandler = (err, req, res, next) => { 7 | console.error(err.stack); 8 | 9 | res.json(404).send('Something broke!'); 10 | }; 11 | 12 | const startServer = port => { 13 | app 14 | .use(bodyParser.urlencoded({extended: false})) 15 | .use(bodyParser.json()) 16 | .use(morgan('dev')) 17 | .use('/', router) 18 | .use(errorHandler); 19 | 20 | app.listen(port); 21 | 22 | console.log('Server was started at http://localhost:' + port); 23 | }; 24 | 25 | module.exports = startServer; 26 | -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/app/routes/create-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../models/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const createUser = (req, res) => { 5 | const { firstName, lastName, telephone, nickName, location, email, password } = req.body; 6 | 7 | const hashedPassword = bcrypt.hashSync(password, 10); 8 | 9 | const nick = new User({ 10 | firstName, 11 | lastName, 12 | telephone, 13 | nickName, 14 | location, 15 | email, 16 | password: hashedPassword 17 | }); 18 | 19 | nick.save((err) => { 20 | if (err) throw err; 21 | 22 | console.log('User saved successfully'); 23 | res.json({ success: true }); 24 | }); 25 | 26 | }; 27 | 28 | module.exports = createUser; -------------------------------------------------------------------------------- /lesson-2/demo/src/helpers/get-route-handler.js: -------------------------------------------------------------------------------- 1 | const hasNumber = myString => /\d/.test(myString); 2 | 3 | const getIdFreeUrl = url => { 4 | // url example : `/users/12345` 5 | const lastIndex = url.lastIndexOf('/'); 6 | const idString = url.slice(lastIndex +1).trim(); 7 | 8 | // url example : `/users` 9 | if (!hasNumber(idString)) { 10 | return url; 11 | } 12 | 13 | const idNumber = +idString; 14 | 15 | if (idNumber && lastIndex !== -1) { 16 | return url.slice(0, lastIndex); 17 | } 18 | 19 | return url; 20 | }; 21 | 22 | const getRouteHandler = (routerConfig, url) => { 23 | const clearUrl = getIdFreeUrl(url); 24 | 25 | return routerConfig[clearUrl]; 26 | }; 27 | 28 | module.exports = getRouteHandler; 29 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/image/save-image-multipart.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer'); 2 | const { uploadFile } = require('../../cloud-storage/service'); 3 | 4 | const storage = multer.memoryStorage(); 5 | 6 | // Применяем настройки 7 | const upload = multer({ storage }); 8 | 9 | const saveImageMultipart = (req, res) => { 10 | const fileObject = req.file; 11 | 12 | uploadFile(fileObject) 13 | .then(imagePublicLink => { 14 | res.json({ status: 'success', src: imagePublicLink }); 15 | }) 16 | .catch(error => { 17 | res.json({ status: 'error', error }); 18 | }) 19 | 20 | }; 21 | 22 | // добавляем промежуточный обработчик для post-multipart запросов 23 | module.exports = () => [upload.single('file'), saveImageMultipart]; -------------------------------------------------------------------------------- /lesson-2/demo/src/server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const url = require('url'); 3 | const fs = require('fs'); 4 | const morgan = require('morgan'); 5 | const router = require('./routes/router'); 6 | const getRouteHandler = require('./helpers/get-route-handler'); 7 | 8 | const logger = morgan('combined'); 9 | 10 | const startServer = port => { 11 | 12 | const server = http.createServer((request, response) => { 13 | // Get route from the request 14 | const parsedUrl = url.parse(request.url); 15 | 16 | // Get router function 17 | const func = getRouteHandler(router, parsedUrl.pathname) || router.default; 18 | 19 | logger(request, response, () => func(request, response)); 20 | }); 21 | 22 | server.listen(port); 23 | }; 24 | 25 | module.exports = startServer; 26 | -------------------------------------------------------------------------------- /lesson-3/img/demo2.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | 3 | var app = express(); 4 | 5 | // добавление middleware ко всем роутам 6 | app.use(requestTime); 7 | 8 | 9 | app.post('/', function (req, res) { 10 | var responseText = 'Hello World!'; 11 | responseText += 'Requested at: ' + req.requestTime + ''; 12 | res.send(responseText); 13 | }); 14 | 15 | app.get('/subscribers/:id', 16 | // добавление middleware к определенному роуту 17 | function checkIfPaidSubscriber(req, res, next) { 18 | if(!req.user.hasPaid) { 19 | 20 | // continue handling this request 21 | next('route'); 22 | } 23 | }, 24 | function getPaidContent(req, res) { 25 | PaidContent.find(function(err, doc) { 26 | if(err) return next(err); 27 | res.json(doc); 28 | }); 29 | }); 30 | 31 | app.listen(3000); -------------------------------------------------------------------------------- /lesson-8/demo/server/src/server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const bodyParser = require('body-parser'); 3 | const morgan = require('morgan'); 4 | const controller = require('./controller'); 5 | 6 | const errorHandler = (err, req, res, next) => { 7 | console.error(err.stack); 8 | 9 | res.json(404).send('No such page'); 10 | }; 11 | 12 | const startServer = port => { 13 | const server = http.createServer(controller.app); 14 | 15 | controller.app 16 | .use(bodyParser.urlencoded({extended: false})) 17 | .use(bodyParser.json()) 18 | .use(morgan('dev')) 19 | .use('/', contoller.routes) 20 | .use(errorHandler); 21 | 22 | contoller.chat(server); 23 | 24 | server.listen(port); 25 | 26 | console.log('Server was started at http://localhost:' + port); 27 | }; 28 | 29 | module.exports = startServer; 30 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/path-module/demo-with-path.js: -------------------------------------------------------------------------------- 1 | // path.join - соединяет все строки с путями в 1 строку https://nodejs.org/dist/latest-v10.x/docs/api/path.html#path_path_join_paths 2 | // path.parse - парсит строку адреса в обьект https://nodejs.org/dist/latest-v10.x/docs/api/path.html#path_path_parse_path 3 | // path.format - превращает обьект с параметрами в строку адреса https://nodejs.org/dist/latest-v10.x/docs/api/path.html#path_path_format_pathobject 4 | 5 | const path = require('path'); 6 | 7 | const newDirectoryName = 'local-database'; 8 | 9 | const productsPath = path.join(__dirname, '..', 'fs-module', newDirectoryName,'output-products.json'); 10 | 11 | const newProductsPath = path.format({ 12 | root: '/', 13 | dir: __dirname, 14 | ext: '.txt', 15 | name: Date.now() 16 | }); 17 | 18 | console.log(newProductsPath); -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/user/create-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../modules/db/schemas/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const createUser = (request, response) => { 5 | const user = request.body; 6 | 7 | const hashedPassword = bcrypt.hashSync(user.password, 10); 8 | const userData = { ...user, password: hashedPassword }; 9 | 10 | const newUser = new User(userData); 11 | 12 | const sendResponse = (user) => { 13 | console.log(user); 14 | 15 | response.json({ 16 | status: 'success', 17 | user 18 | }); 19 | }; 20 | 21 | const sendError = () => { 22 | response.status(400); 23 | response.json({ 24 | error: 'user was not saved' 25 | }); 26 | }; 27 | 28 | newUser.save() 29 | .then(sendResponse) 30 | .catch(sendError) 31 | 32 | }; 33 | 34 | module.exports = createUser; -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-playground", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "nodemon server.js", 8 | "debug": "nodemon --inspect server.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/burnjohn/server-playground.git" 13 | }, 14 | "author": "Ivan Lapa", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/burnjohn/server-playground/issues" 18 | }, 19 | "homepage": "https://github.com/burnjohn/server-playground#readme", 20 | "dependencies": { 21 | "bcrypt": "^3.0.0", 22 | "jsonwebtoken": "^8.3.0", 23 | "body-parser": "^1.18.3", 24 | "express": "^4.16.3", 25 | "mongoose": "^5.2.14", 26 | "morgan": "^1.9.1", 27 | "nodemon": "^1.18.10" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/user/create-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const createUser = (request, response) => { 5 | const user = request.body; 6 | const hashedPassword = bcrypt.hashSync(user.password, 10); 7 | const userData = Object.assign({}, user, { 8 | password: hashedPassword 9 | }); 10 | 11 | const newUser = new User(userData); 12 | 13 | const sendResponse = (user) => { 14 | console.log(user); 15 | 16 | response.json({ 17 | status: 'success', 18 | user 19 | }); 20 | }; 21 | 22 | const sendError = () => { 23 | response.status(400); 24 | response.json({ 25 | error: 'user was not saved' 26 | }); 27 | }; 28 | 29 | newUser.save() 30 | .then(sendResponse) 31 | .catch(sendError) 32 | 33 | }; 34 | 35 | module.exports = createUser; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/user/create-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const createUser = (request, response) => { 5 | const user = request.body; 6 | const hashedPassword = bcrypt.hashSync(user.password, 10); 7 | const userData = Object.assign({}, user, { 8 | password: hashedPassword 9 | }); 10 | 11 | const newUser = new User(userData); 12 | 13 | const sendResponse = (user) => { 14 | console.log(user); 15 | 16 | response.json({ 17 | status: 'success', 18 | user 19 | }); 20 | }; 21 | 22 | const sendError = () => { 23 | response.status(400); 24 | response.json({ 25 | error: 'user was not saved' 26 | }); 27 | }; 28 | 29 | newUser.save() 30 | .then(sendResponse) 31 | .catch(sendError) 32 | 33 | }; 34 | 35 | module.exports = createUser; -------------------------------------------------------------------------------- /lesson-3/demo/src/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | const bodyParser = require('body-parser'); 4 | const app = require('./modules/app'); 5 | const morgan = require('morgan'); 6 | const router = require('./routes/router'); 7 | 8 | const errorHandler = (err, req, res, next) => { 9 | res 10 | .status(500) 11 | .send('Error found: ' + err.stack); 12 | }; 13 | 14 | const staticPath = path.join(__dirname, '..', 'assets'); 15 | 16 | const startServer = port => { 17 | app 18 | .use(bodyParser.urlencoded({ extended: false })) 19 | .use(bodyParser.json()) 20 | .use(morgan('dev')) 21 | .use(express.static(staticPath)) 22 | .use('/', router) 23 | .use(errorHandler); 24 | 25 | app.listen(port); 26 | 27 | console.log('Server was started at http://localhost:' + port); 28 | }; 29 | 30 | module.exports = startServer; 31 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const bodyParser = require('body-parser'); 3 | const app = require('./modules/app'); 4 | const morgan = require('morgan'); 5 | const router = require('./routes/router'); 6 | const initChat = require('./modules/chat/init-chat'); 7 | 8 | const errorHandler = (err, req, res, next) => { 9 | console.error(err.stack); 10 | 11 | res.json(404).send('No such page'); 12 | }; 13 | 14 | const startServer = port => { 15 | const server = http.createServer(app); 16 | 17 | app 18 | .use(bodyParser.urlencoded({extended: false})) 19 | .use(bodyParser.json()) 20 | .use(morgan('dev')) 21 | .use('/', router) 22 | .use(errorHandler); 23 | 24 | initChat(server); 25 | 26 | server.listen(port); 27 | 28 | console.log('Server was started at http://localhost:' + port); 29 | }; 30 | 31 | module.exports = startServer; 32 | -------------------------------------------------------------------------------- /lesson-4/demo/streams/read-stream.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const myReadStream = fs.createReadStream(__dirname + '/readme.txt', {encoding: 'utf8'}); 4 | 5 | let chunkIndex = 0; 6 | 7 | myReadStream.on('open', () => { 8 | console.log('WAS OPENED'); 9 | }); 10 | 11 | myReadStream.on('data', chunk => { 12 | chunkIndex++; 13 | 14 | debugger 15 | 16 | if (chunkIndex === 3) { 17 | myReadStream.pause(); 18 | console.log('WAS PAUSED: ', !myReadStream.isPaused()); 19 | 20 | setTimeout(() => { 21 | 22 | myReadStream.resume(); 23 | console.log('WAS STARTED: ', !myReadStream.isPaused()); 24 | 25 | }, 3000) 26 | } 27 | 28 | console.log('New chunk received: ', chunkIndex); 29 | }); 30 | 31 | myReadStream.on('close', () => { 32 | console.log('WAS CLOSED'); 33 | }); 34 | 35 | myReadStream.on('error', error => { 36 | console.log('Error was caught: ', error); 37 | }); -------------------------------------------------------------------------------- /lesson-3/demo/src/routes/router.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mainRoute = require('./main/main'); 3 | const getUser = require('./user/get-user'); 4 | const getSaveImageHandlers = require('./image/save-image-multipart'); 5 | const createUser = require('./user/create-user'); 6 | 7 | const apiRoutes = express.Router(); 8 | 9 | const middlewareExample = (req, resp, next) => { 10 | if (req.body.userName) { 11 | next(); 12 | return; 13 | } 14 | 15 | resp.status(400); 16 | resp.json({ 17 | error: 'user has no "userName" field' 18 | }) 19 | }; 20 | 21 | apiRoutes 22 | .get('/', mainRoute) 23 | .get('/users/:userId', getUser) 24 | 25 | .post('/users', middlewareExample, createUser) 26 | .post('/image', getSaveImageHandlers()) 27 | .get('*', (req, res, next) => { 28 | res.status(404).send('Route not exists'); 29 | }); 30 | 31 | 32 | module.exports = apiRoutes; 33 | -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/router.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mainRoute = require('./main/main'); 3 | const getImageRoute = require('./image/get-image'); 4 | const getUser = require('./user/get-user'); 5 | const deleteUser = require('./user/delete-user'); 6 | const getAllUser = require('./user/get-all-users'); 7 | const getSaveImageHandlers = require('./image/save-image-multipart'); 8 | const createUser = require('./user/create-user'); 9 | const updateUser = require('./user/update-user'); 10 | 11 | const apiRoutes = express.Router(); 12 | 13 | apiRoutes 14 | .get('/', mainRoute) 15 | .get('/image', getImageRoute) 16 | .post('/image', getSaveImageHandlers()) 17 | 18 | .get('/users', getAllUser) 19 | .get('/users/:id', getUser) 20 | .delete('/users/:id', deleteUser) 21 | .put('/users/:id', updateUser) 22 | .post('/users', createUser); 23 | 24 | 25 | module.exports = apiRoutes; 26 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/router.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mainRoute = require('./main/main'); 3 | const getImageRoute = require('./image/get-image'); 4 | const getUser = require('./user/get-user'); 5 | const deleteUser = require('./user/delete-user'); 6 | const getAllUser = require('./user/get-all-users'); 7 | const getSaveImageHandlers = require('./image/save-image-multipart'); 8 | const createUser = require('./user/create-user'); 9 | const updateUser = require('./user/update-user'); 10 | 11 | const apiRoutes = express.Router(); 12 | 13 | apiRoutes 14 | .get('/', mainRoute) 15 | .get('/image', getImageRoute) 16 | .post('/image', getSaveImageHandlers()) 17 | 18 | .get('/users', getAllUser) 19 | .get('/users/:id', getUser) 20 | .delete('/users/:id', deleteUser) 21 | .put('/users/:id', updateUser) 22 | .post('/users', createUser); 23 | 24 | 25 | module.exports = apiRoutes; 26 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/chat/chatroom-manager.js: -------------------------------------------------------------------------------- 1 | const createChatRoom = require('./chatroom'); 2 | const chatRoomTemplates = require('./templates/chatrooms'); 3 | 4 | // Все доступные комнаты 5 | const chatRooms = {}; 6 | 7 | // Создание комнат с темплейта 8 | chatRoomTemplates.forEach(chatRoom => { 9 | chatRooms[chatRoom.name] = createChatRoom(chatRoom); 10 | }); 11 | 12 | // Удалить пользователя из всех чат комнат 13 | const removeClient = (client) => { 14 | Object.values(chatRooms).forEach(c => c.removeUser(client)); 15 | }; 16 | 17 | // взять комнату 18 | const getChatRoomByName = (chatroomName) => { 19 | return chatRooms[chatroomName]; 20 | }; 21 | 22 | // взять все комнаты 23 | const getAllCharRooms = () => { 24 | return Object.values(chatRooms).map(c => c.getChatRoomInfo()); 25 | }; 26 | 27 | module.exports = { 28 | removeClient, 29 | getChatRoomByName, 30 | getAllCharRooms, 31 | }; 32 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/router.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mainRoute = require('./main/main'); 3 | const getImageRoute = require('./image/get-image'); 4 | const getUser = require('./user/get-user'); 5 | const deleteUser = require('./user/delete-user'); 6 | const getAllUser = require('./user/get-all-users'); 7 | const getSaveImageHandlers = require('./image/save-image-multipart'); 8 | const createUser = require('./user/create-user'); 9 | const updateUser = require('./user/update-user'); 10 | 11 | const apiRoutes = express.Router(); 12 | 13 | apiRoutes 14 | .get('/', mainRoute) 15 | .get('/image', getImageRoute) 16 | .post('/image', getSaveImageHandlers()) 17 | 18 | .get('/users', getAllUser) 19 | .get('/users/:id', getUser) 20 | .delete('/users/:id', deleteUser) 21 | .put('/users/:id', updateUser) 22 | .post('/users', createUser); 23 | 24 | 25 | module.exports = apiRoutes; 26 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/chat/chatroom-manager.js: -------------------------------------------------------------------------------- 1 | const createChatRoom = require('./chatroom'); 2 | const chatRoomTemplates = require('./templates/chatrooms'); 3 | 4 | // Все доступные комнаты 5 | const chatRooms = {}; 6 | 7 | // Создание комнат с темплейта 8 | chatRoomTemplates.forEach(chatRoom => { 9 | chatRooms[chatRoom.name] = createChatRoom(chatRoom); 10 | }); 11 | 12 | // Удалить пользователя из всех чат комнат 13 | const removeClient = (client) => { 14 | Object.values(chatRooms).forEach(c => c.removeUser(client)); 15 | }; 16 | 17 | // взять комнату 18 | const getChatRoomByName = (chatroomName) => { 19 | return chatRooms[chatroomName]; 20 | }; 21 | 22 | // взять все комнаты 23 | const getAllCharRooms = () => { 24 | return Object.values(chatRooms).map(c => c.getChatRoomInfo()); 25 | }; 26 | 27 | module.exports = { 28 | removeClient, 29 | getChatRoomByName, 30 | getAllCharRooms, 31 | }; 32 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mainRoute = require('./main/main'); 3 | const getImageRoute = require('./image/get-image'); 4 | const getUser = require('./user/get-user'); 5 | const deleteUser = require('./user/delete-user'); 6 | const getAllUser = require('./user/get-all-users'); 7 | const getSaveImageHandlers = require('./image/save-image-multipart'); 8 | const createUser = require('./user/create-user'); 9 | const updateUser = require('./user/update-user'); 10 | 11 | const apiRoutes = express.Router(); 12 | 13 | apiRoutes 14 | .get('/', mainRoute) 15 | .get('/image', getImageRoute) 16 | .post('/image', getSaveImageHandlers()) 17 | 18 | .get('/users', getAllUser) 19 | .get('/users/:id', getUser) 20 | .delete('/users/:id', deleteUser) 21 | .put('/users/:id', updateUser) 22 | .post('/users', createUser); 23 | 24 | 25 | module.exports = apiRoutes; 26 | -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/app/modules/check-token.js: -------------------------------------------------------------------------------- 1 | const app = require('./app'); 2 | const jwt = require('jsonwebtoken'); 3 | 4 | // POST { token: } 5 | 6 | // GET ?token= 7 | 8 | // header { x-access-token: } 9 | 10 | const getToken = req => req.body.token || req.query.token || req.headers['x-access-token']; 11 | 12 | const checkToken = (req, res, next) => { 13 | const token = getToken(req); 14 | const secretKey = app.get('superSecret'); 15 | 16 | if (!token) { 17 | return res.status(403).send({ 18 | success: false, 19 | message: 'No token provided.' 20 | }); 21 | } 22 | 23 | 24 | jwt.verify(token, secretKey, (err, decoded) => { 25 | if (err) { 26 | return res.json({ 27 | success: false, 28 | message: 'Failed to authenticate token.' 29 | }); 30 | } 31 | 32 | req.decoded = decoded; 33 | next(); 34 | }); 35 | }; 36 | 37 | module.exports = checkToken; -------------------------------------------------------------------------------- /lesson-1/demo/src/routes/users/sign-up-route.js: -------------------------------------------------------------------------------- 1 | const qs = require('querystring'); 2 | 3 | const saveUser = user => { 4 | // получить файл с юзером 5 | // найти путь папки users 6 | // сохранить туда файл 7 | }; 8 | 9 | const signUpRoute = (request, response) => { 10 | // Взять данные что пришли 11 | 12 | if (request.method === 'POST') { 13 | let body = ''; 14 | 15 | request.on('data', function (data) { 16 | body = body + data; 17 | 18 | console.log('Incoming data!!!!'); 19 | }); 20 | 21 | request.on('end', function () { 22 | const post = qs.parse(body); 23 | console.log(post); 24 | }); 25 | } 26 | 27 | // Взять username с данных, сохранить в переменную 28 | 29 | // Сохраняем данные в .json 30 | 31 | // Сохранить .json в папку users 32 | 33 | // Отправляем файл в ответе с данными юзера 34 | // использовать response 35 | }; 36 | 37 | module.exports = signUpRoute; -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/ChatroomPreview.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components' 3 | import Paper from 'material-ui/Paper'; 4 | import { Card, CardMedia, CardTitle } from 'material-ui/Card'; 5 | 6 | 7 | const Wrapper = styled.div` 8 | cursor: pointer; 9 | ` 10 | 11 | const getCardTitleStyle = () => ({ 12 | display: 'flex', 13 | alignItems: 'center' 14 | }) 15 | 16 | export default ({ chatroom, onEnter }) => ( 17 | 21 | 22 | 23 | 29 | } 30 | > 31 | 32 | 33 | 34 | 35 | 36 | ) 37 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/user/create.js: -------------------------------------------------------------------------------- 1 | const core = require('../../core'); 2 | const { pick } = require('lodash'); 3 | const User = require('../db/schemas/user'); 4 | const bcrypt = require('bcrypt'); 5 | 6 | const saveUserInDB = (userData) => new User(userData); 7 | 8 | const pickUserFields = (user) => 9 | pick(user, [ 10 | 'username', 11 | 'telephone', 12 | 'password', 13 | 'email' 14 | ]); 15 | 16 | const createUser = (userInput) => new Promise((resolve, reject) =>{ 17 | const errorsList = core.inputCheck.user(userInput); 18 | 19 | if (errorsList.length) { 20 | reject(errorsList); 21 | return; 22 | } 23 | 24 | const hashedPassword = bcrypt.hashSync(user.password, 10); 25 | const userData = Object.assign({}, user, { 26 | password: hashedPassword 27 | }); 28 | 29 | return saveUserInDB(userData) 30 | .then(pickUserFields) 31 | .then(resolve) 32 | .catch(reject); 33 | }); 34 | 35 | export default createUser -------------------------------------------------------------------------------- /z-demo-10/demo/src/cloud-storage/service.js: -------------------------------------------------------------------------------- 1 | const { bucketName } = require('./config'); 2 | const bucket = require('./index'); 3 | 4 | const getPublicUrl = filename => { 5 | return `https://storage.googleapis.com/${bucketName}/${filename}`; 6 | }; 7 | 8 | const uploadFile = fileData => new Promise( 9 | (resolve, reject) => { 10 | const fileName = fileData.originalname; 11 | const file = bucket.file(fileName); 12 | 13 | const stream = file.createWriteStream({ 14 | metadata: { 15 | contentType: fileData.mimetype 16 | }, 17 | gzip: true, 18 | public: true, 19 | resumable: false 20 | }); 21 | 22 | stream.on('error', (err) => { 23 | reject(err); 24 | }); 25 | 26 | stream.on('finish', () => { 27 | 28 | file.makePublic().then(() => { 29 | resolve(getPublicUrl(fileName)); 30 | }); 31 | }); 32 | 33 | stream.end(fileData.buffer); 34 | }); 35 | 36 | module.exports = { 37 | uploadFile 38 | }; -------------------------------------------------------------------------------- /lesson-6/demo/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "websocket-chat", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "start": "webpack-dev-server" 6 | }, 7 | "author": "justadudewhohacks", 8 | "license": "MIT", 9 | "dependencies": { 10 | "babel-core": "^6.26.0", 11 | "babel-loader": "^7.1.2", 12 | "babel-preset-es2015": "^6.24.1", 13 | "babel-preset-react": "^6.24.1", 14 | "material-ui": "^0.20.0", 15 | "react": "16.2.0", 16 | "react-dom": "^16.2.0", 17 | "react-hot-loader": "^3.1.3", 18 | "react-router-dom": "^4.2.2", 19 | "react-tap-event-plugin": "^3.0.2", 20 | "socket.io": "^2.0.4", 21 | "styled-components": "^3.1.6", 22 | "webpack": "^3.11.0", 23 | "webpack-dev-server": "^2.11.1" 24 | }, 25 | "devDependencies": { 26 | "eslint": "^4.17.0", 27 | "eslint-config-airbnb": "^16.1.0", 28 | "eslint-plugin-import": "^2.8.0", 29 | "eslint-plugin-jsx-a11y": "^6.0.3", 30 | "eslint-plugin-react": "^7.6.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /z-demo-10/demo/src/routes/user/update-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const updateUser = (request, response) => { 5 | const user = request.body; 6 | const id = request.params.id; 7 | 8 | if (user.password) { 9 | user.password = bcrypt.hashSync(user.password, 10); 10 | } 11 | 12 | const sendError = () => { 13 | response.status(400); 14 | response.json({ 15 | status: 'error', 16 | text: 'there is no such user' 17 | }); 18 | }; 19 | 20 | const sendResponse = (newUser) => { 21 | if (!newUser) { 22 | return sendError(); 23 | } 24 | 25 | response.json({ 26 | status: 'success', 27 | user: newUser 28 | }); 29 | }; 30 | 31 | User 32 | .findOneAndUpdate( 33 | { _id: id }, 34 | user, 35 | { new: true } // вернуть обновленный документ 36 | ) 37 | .then(sendResponse) 38 | .catch(sendError) 39 | 40 | }; 41 | 42 | module.exports = updateUser; -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/user/update-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../modules/db/schemas/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const updateUser = (request, response) => { 5 | const user = request.body; 6 | const id = request.params.id; 7 | 8 | if (user.password) { 9 | user.password = bcrypt.hashSync(user.password, 10); 10 | } 11 | 12 | const sendError = () => { 13 | response.status(400); 14 | response.json({ 15 | status: 'error', 16 | text: 'there is no such user' 17 | }); 18 | }; 19 | 20 | const sendResponse = (newUser) => { 21 | if (!newUser) { 22 | return sendError(); 23 | } 24 | 25 | response.json({ 26 | status: 'success', 27 | user: newUser 28 | }); 29 | }; 30 | 31 | User 32 | .findOneAndUpdate( 33 | { _id: id }, 34 | user, 35 | { new: true } // вернуть обновленный документ 36 | ) 37 | .then(sendResponse) 38 | .catch(sendError) 39 | 40 | }; 41 | 42 | module.exports = updateUser; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/user/update-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const updateUser = (request, response) => { 5 | const user = request.body; 6 | const id = request.params.id; 7 | 8 | if (user.password) { 9 | user.password = bcrypt.hashSync(user.password, 10); 10 | } 11 | 12 | const sendError = () => { 13 | response.status(400); 14 | response.json({ 15 | status: 'error', 16 | text: 'there is no such user' 17 | }); 18 | }; 19 | 20 | const sendResponse = (newUser) => { 21 | if (!newUser) { 22 | return sendError(); 23 | } 24 | 25 | response.json({ 26 | status: 'success', 27 | user: newUser 28 | }); 29 | }; 30 | 31 | User 32 | .findOneAndUpdate( 33 | { _id: id }, 34 | user, 35 | { new: true } // вернуть обновленный документ 36 | ) 37 | .then(sendResponse) 38 | .catch(sendError) 39 | 40 | }; 41 | 42 | module.exports = updateUser; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/users/update-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/user'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const updateUser = (request, response) => { 5 | const user = request.body; 6 | const id = request.params.id; 7 | 8 | if (user.password) { 9 | user.password = bcrypt.hashSync(user.password, 10); 10 | } 11 | 12 | const sendError = () => { 13 | response.status(400); 14 | response.json({ 15 | status: 'error', 16 | text: 'there is no such user' 17 | }); 18 | }; 19 | 20 | const sendResponse = (newUser) => { 21 | if (!newUser) { 22 | return sendError(); 23 | } 24 | 25 | response.json({ 26 | status: 'success', 27 | user: newUser 28 | }); 29 | }; 30 | 31 | User 32 | .findOneAndUpdate( 33 | { _id: id }, 34 | user, 35 | { new: true } // вернуть обновленный документ 36 | ) 37 | .then(sendResponse) 38 | .catch(sendError) 39 | 40 | }; 41 | 42 | module.exports = updateUser; -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/users/update-user.js: -------------------------------------------------------------------------------- 1 | const User = require('../../db/schemas/users'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const updateUser = (request, response) => { 5 | const user = request.body; 6 | const id = request.params.id; 7 | 8 | if (user.password) { 9 | user.password = bcrypt.hashSync(user.password, 10); 10 | } 11 | 12 | const sendError = () => { 13 | response.status(400); 14 | response.json({ 15 | status: 'error', 16 | text: 'there is no such users' 17 | }); 18 | }; 19 | 20 | const sendResponse = (newUser) => { 21 | if (!newUser) { 22 | return sendError(); 23 | } 24 | 25 | response.json({ 26 | status: 'success', 27 | user: newUser 28 | }); 29 | }; 30 | 31 | User 32 | .findOneAndUpdate( 33 | { _id: id }, 34 | user, 35 | { new: true } // вернуть обновленный документ 36 | ) 37 | .then(sendResponse) 38 | .catch(sendError) 39 | 40 | }; 41 | 42 | module.exports = updateUser; -------------------------------------------------------------------------------- /lesson-1/screencast-materials/node-js-modules/no-modules/all-in-one.js: -------------------------------------------------------------------------------- 1 | 2 | const ordersStorage = { 3 | '12345-bob': { 4 | items: [ 5 | { name: 'pizza', count: 2 }, 6 | { name: 'beer', count: 1 }, 7 | ], 8 | time: 1555242804290, 9 | id: 123 10 | } 11 | }; 12 | 13 | const dataBase = { 14 | saveOrder(order, userId) { 15 | 16 | ordersStorage[userId] = order; 17 | 18 | } 19 | }; 20 | 21 | const getMissedOrderFields = (order) => { 22 | if (!order.items) { 23 | return 'items are missing'; 24 | } 25 | 26 | return null; 27 | }; 28 | 29 | const orderController = { 30 | saveOrder(order) { 31 | 32 | if (getMissedOrderFields(order)) { 33 | return; 34 | } 35 | 36 | const storage = ordersStorage; 37 | 38 | storage[userId] = null; 39 | 40 | dataBase.saveOrder(order, userId); 41 | } 42 | }; 43 | 44 | orderController.saveOrder({ 45 | items: [ 46 | { name: 'pizza', count: 2 }, 47 | { name: 'beer', count: 1 }, 48 | ], 49 | time: 1555242804290, 50 | userId: 123 51 | }); -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/routes/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mainRoute = require('../main'); 3 | const getUser = require('../users/get-user'); 4 | const deleteUser = require('../users/delete-user'); 5 | const getAllUser = require('../users/get-all-users'); 6 | const createUser = require('../users/create-user'); 7 | const updateUser = require('../users/update-user'); 8 | 9 | const apiRoutes = express.Router(); 10 | 11 | const checkAuth = (req, resp, next) => { 12 | const userId = req.params.id; 13 | const userToken = req.body.authToken; 14 | const userData = decryptUser(userToken); 15 | 16 | if (userData.id === userId) { 17 | next(); 18 | } else { 19 | resp.text('Not authorised'); 20 | } 21 | }; 22 | 23 | apiRoutes 24 | .get('/', mainRoute) 25 | .get('/users', getAllUser) 26 | 27 | 28 | .get('/users/:id', checkAuth, getUser) 29 | 30 | .delete('/users/:id', deleteUser) 31 | .put('/users/:id', updateUser) 32 | .post('/users', createUser); 33 | 34 | 35 | module.exports = apiRoutes; 36 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/http-module/products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 19112831, 4 | "sku": 1120001, 5 | "name": "Пицца Пепперони с томатами", 6 | "description": "Пицца пепперони - очень популярный вид пиццы как в Европе, так и в Америке. Она получила свое название благодаря основному ингредиенту солями пепперони, который и отличает ее от всех остальных видов пицц. Он имеет острый вкус и при запекании покрывается хрустящей жирной корочкой.", 7 | "price": "100", 8 | "currency": "UAN", 9 | "creatorId": 1, 10 | "categories": ["pizza"] 11 | }, 12 | { 13 | "id": 19112832, 14 | "sku": 1120002, 15 | "name": "Пицца Маргарита", 16 | "description": "Пожалуй, самая популярная в мире, даже меню любой пиццерии начинается, как правило, именно с неё. Состав этой пиццы необычайно прост, её основные ингредиенты: сыр моцарелла, спелые помидоры и листья свежего базилика, которые придают ей неповторимый вкус и аромат.", 17 | "price": "80", 18 | "currency": "UAN", 19 | "creatorId": 1, 20 | "categories": ["pizza"] 21 | } 22 | ] -------------------------------------------------------------------------------- /lesson-1/screencast-materials/fs-module/local-database/output-products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 19112831, 4 | "sku": 1120001, 5 | "name": "Пицца Пепперони с томатами", 6 | "description": "Пицца пепперони - очень популярный вид пиццы как в Европе, так и в Америке. Она получила свое название благодаря основному ингредиенту солями пепперони, который и отличает ее от всех остальных видов пицц. Он имеет острый вкус и при запекании покрывается хрустящей жирной корочкой.", 7 | "price": "100", 8 | "currency": "UAN", 9 | "creatorId": 1, 10 | "categories": ["pizza"] 11 | }, 12 | { 13 | "id": 19112832, 14 | "sku": 1120002, 15 | "name": "Пицца Маргарита", 16 | "description": "Пожалуй, самая популярная в мире, даже меню любой пиццерии начинается, как правило, именно с неё. Состав этой пиццы необычайно прост, её основные ингредиенты: сыр моцарелла, спелые помидоры и листья свежего базилика, которые придают ей неповторимый вкус и аромат.", 17 | "price": "80", 18 | "currency": "UAN", 19 | "creatorId": 1, 20 | "categories": ["pizza"] 21 | } 22 | ] -------------------------------------------------------------------------------- /lesson-6/demo/client/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | entry: [ 6 | 'react-hot-loader/patch', 7 | 'webpack-dev-server/client?http://localhost:3001', 8 | 'webpack/hot/only-dev-server', 9 | path.resolve(__dirname, 'scripts', 'index.jsx'), 10 | ], 11 | resolve: { 12 | modules: [path.resolve(__dirname, 'node_modules')], 13 | extensions: ['*', '.js', '.jsx'], 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.(js|jsx)$/, 19 | exclude: /node_modules/, 20 | use: ['babel-loader'], 21 | }, 22 | ], 23 | }, 24 | output: { 25 | path: path.resolve(__dirname, 'public'), 26 | publicPath: '/', 27 | filename: 'bundle.js', 28 | }, 29 | plugins: [ 30 | new webpack.HotModuleReplacementPlugin(), 31 | new webpack.DefinePlugin({ 32 | 'process.env': { 33 | NODE_ENV: '"development"', 34 | }, 35 | }), 36 | ], 37 | devServer: { 38 | port: 3001, 39 | contentBase: path.resolve(__dirname, 'public'), 40 | hot: true, 41 | historyApiFallback: true, 42 | }, 43 | devtool: 'source-map', 44 | }; -------------------------------------------------------------------------------- /lesson-4/demo/streams/write-stream-transform.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { Transform } = require('stream'); 3 | 4 | const myReadStream = fs.createReadStream(__dirname + '/readme.txt', {encoding: 'utf8'}); 5 | const myWriteStream = fs.createWriteStream(__dirname + '/readme_created.txt'); 6 | 7 | myWriteStream.on('open', () => { 8 | console.log('File translation was started'); 9 | }); 10 | 11 | myWriteStream.on('finish', () => { 12 | console.log('File was translated'); 13 | }); 14 | 15 | const dictionary = { 16 | widow: 'окно', 17 | brother: 'брат', 18 | books: 'книги' 19 | }; 20 | 21 | const upperCaseTransform = new Transform({ 22 | transform: (chunk, encoding, next) => { 23 | const newData = chunk 24 | .toString() 25 | .split(' ') 26 | .map(word => { 27 | const lowerCaseWord = word.toLowerCase().trim(); 28 | 29 | if (dictionary[lowerCaseWord]) { 30 | return dictionary[lowerCaseWord]; 31 | } 32 | 33 | return word; 34 | }) 35 | .join(' '); 36 | 37 | next(null, newData); 38 | } 39 | }); 40 | 41 | upperCaseTransform.on('error', console.log); 42 | 43 | myReadStream 44 | .pipe(upperCaseTransform) 45 | .pipe(myWriteStream); -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const morgan = require('morgan'); 4 | const mongoose = require('mongoose'); 5 | const config = require('./config'); 6 | const findUser = require('./app/routes/find-user'); 7 | const createUser = require('./app/routes/create-user'); 8 | const auth = require('./app/routes/auth'); 9 | const app = require('./app/modules/app'); 10 | const verifyToken = require('./app/modules/check-token'); 11 | 12 | const port = process.env.PORT || 8080; 13 | 14 | mongoose.connect(config.database, { useNewUrlParser: true }); 15 | 16 | app 17 | .set('superSecret', config.secret) 18 | .use(bodyParser.urlencoded({ extended: false })) 19 | .use(bodyParser.json()) 20 | .use(morgan('dev')); 21 | 22 | const apiRoutes = express.Router(); 23 | 24 | apiRoutes 25 | .post('/authenticate', auth) 26 | .use(verifyToken) 27 | .get('/', (req, res) => { 28 | res.send({ message: 'Welcome to the API!' }); 29 | }) 30 | .get('/users', findUser) 31 | .post('/users', createUser); 32 | 33 | 34 | app.use('/api', apiRoutes); 35 | 36 | app.listen(port); 37 | console.log('Server is running at http://localhost:' + port); 38 | 39 | global.app = app; 40 | 41 | -------------------------------------------------------------------------------- /lesson-7/JSON-web-token/app/routes/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | const User = require('../models/user'); 3 | const bcrypt = require('bcrypt'); 4 | 5 | const errorResp = { 6 | success: false, 7 | message: 'Authentication failed.', 8 | }; 9 | 10 | const passwMatches = (passw1, hash) => bcrypt.compareSync(passw1, hash); 11 | 12 | const generateToken = paramsForTokenGeneration => { 13 | const secretKey = app.get('superSecret'); 14 | 15 | return jwt.sign(paramsForTokenGeneration, secretKey, { 16 | expiresIn: 60 * 60 * 24 17 | }) 18 | }; 19 | 20 | const authenticate = (req, res) => { 21 | const { id: userId, password } = req.body; 22 | 23 | User.findById(userId, onFind); 24 | 25 | function onFind(err, user) { 26 | if (err) throw err; 27 | 28 | const correctPassword = passwMatches(password, user.password); 29 | 30 | if (!user || !correctPassword) { 31 | res.json(errorResp); 32 | return; 33 | } 34 | 35 | const payload = { 36 | password, 37 | userId 38 | }; 39 | 40 | const token = generateToken(payload); 41 | 42 | res.json({ 43 | success: true, 44 | message: 'Enjoy your token!', 45 | token: token, 46 | }); 47 | 48 | } 49 | }; 50 | 51 | module.exports = authenticate; -------------------------------------------------------------------------------- /lesson-3/demo/src/routes/user/create-user.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const util = require('util'); 4 | 5 | const usersFolder = path.resolve(__dirname, '../../../', 'data/users'); 6 | 7 | // PROMISIFY function example 8 | // 9 | // const writeFile = (src, content) => { 10 | // return new Promise((resolve, reject) => { 11 | // fs.writeFile(src, content, resolve); 12 | // }); 13 | // }; 14 | 15 | const writeFile = util.promisify(fs.writeFile); 16 | 17 | const saveNewUser = (fileName, data) => { 18 | const src = path.resolve(usersFolder, fileName + '.json'); 19 | const dataStr = JSON.stringify(data); 20 | 21 | return writeFile(src, dataStr); 22 | }; 23 | 24 | const createUser = (request, response) => { 25 | const user = request.body; 26 | const userData = { ...user, id: Math.random() }; 27 | 28 | const fileName = userData.userName.toLowerCase() + userData.id; 29 | 30 | const sendResponse = () => { 31 | response.json({ 32 | status: 'success', 33 | user: userData 34 | }); 35 | }; 36 | 37 | const sendError = () => { 38 | response.status(400); 39 | response.json({ 40 | error: 'user was not saved' 41 | }); 42 | }; 43 | 44 | saveNewUser(fileName, userData) 45 | .then(sendResponse) 46 | .catch(sendError); 47 | 48 | }; 49 | 50 | module.exports = createUser; 51 | -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/socket.js: -------------------------------------------------------------------------------- 1 | const io = require('socket.io-client'); 2 | 3 | const getChatHandlers = () => { 4 | const socket = io.connect('http://localhost:80'); 5 | 6 | function registerHandler(onMessageReceived) { 7 | socket.on('message', onMessageReceived); 8 | } 9 | 10 | function unregisterHandler() { 11 | socket.off('message'); 12 | } 13 | 14 | socket.on('error', function(err) { 15 | console.log('received socket error:'); 16 | console.log(err); 17 | }); 18 | 19 | function register(name, cb) { 20 | socket.emit('register', name, cb); 21 | } 22 | 23 | function join(chatRoomName, cb) { 24 | socket.emit('join', chatRoomName, cb); 25 | } 26 | 27 | function leave(chatRoomName, cb) { 28 | socket.emit('leave', chatRoomName, cb); 29 | } 30 | 31 | function message(chatRoomName, msg, cb) { 32 | socket.emit('message', {chatRoomName, message: msg}, cb); 33 | } 34 | 35 | function getChatrooms(cb) { 36 | socket.emit('chatrooms', cb); 37 | } 38 | 39 | function getAvailableUsers(cb) { 40 | socket.emit('availableUsers', cb); 41 | } 42 | 43 | return { 44 | register, 45 | join, 46 | leave, 47 | message, 48 | getChatrooms, 49 | getAvailableUsers, 50 | registerHandler, 51 | unregisterHandler, 52 | }; 53 | }; 54 | 55 | export default getChatHandlers; 56 | 57 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/chat/chatroom.js: -------------------------------------------------------------------------------- 1 | const createChatRoom = ({ name, image }) => { 2 | const members = {}; 3 | let chatHistory = []; 4 | 5 | // Отправить сообщение всем юзерам в комнате 6 | const broadcastMessage = (message) => { 7 | console.log('Message got: ', message); 8 | 9 | const allRoomMembers = Object.values(members); 10 | 11 | allRoomMembers.forEach(member => { 12 | member.emit('message', message) 13 | }); 14 | }; 15 | 16 | // Добавить запись в историю сообщений комнаты 17 | const addEntry = (entry) => { 18 | chatHistory = chatHistory.concat(entry); 19 | }; 20 | 21 | // Получить историю сообщений комнаты 22 | const getChatHistory = () => { 23 | return chatHistory.slice(); 24 | }; 25 | 26 | // Добавляем пользователя в комнату 27 | const addUser = (user) => { 28 | console.log('User added'); 29 | members[user.id] = user; 30 | }; 31 | 32 | // Удаляем пользователя из комнаты 33 | const removeUser = (user) => { 34 | console.log('User removed'); 35 | 36 | delete members[user.id]; 37 | }; 38 | 39 | // Получить информацию по комнате 40 | const getChatRoomInfo = () => ({ 41 | name, 42 | image, 43 | numMembers: members.size, 44 | }); 45 | 46 | return { 47 | broadcastMessage, 48 | addEntry, 49 | getChatHistory, 50 | addUser, 51 | removeUser, 52 | getChatRoomInfo, 53 | }; 54 | }; 55 | 56 | module.exports = createChatRoom; 57 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/chat/chatroom.js: -------------------------------------------------------------------------------- 1 | const createChatRoom = ({ name, image }) => { 2 | const members = {}; 3 | let chatHistory = []; 4 | 5 | // Отправить сообщение всем юзерам в комнате 6 | const broadcastMessage = (message) => { 7 | console.log('Message got: ', message); 8 | 9 | const allRoomMembers = Object.values(members); 10 | 11 | allRoomMembers.forEach(member => { 12 | member.emit('message', message) 13 | }); 14 | }; 15 | 16 | // Добавить запись в историю сообщений комнаты 17 | const addEntry = (entry) => { 18 | chatHistory = chatHistory.concat(entry); 19 | }; 20 | 21 | // Получить историю сообщений комнаты 22 | const getChatHistory = () => { 23 | return chatHistory.slice(); 24 | }; 25 | 26 | // Добавляем пользователя в комнату 27 | const addUser = (user) => { 28 | console.log('User added'); 29 | members[user.id] = user; 30 | }; 31 | 32 | // Удаляем пользователя из комнаты 33 | const removeUser = (user) => { 34 | console.log('User removed'); 35 | 36 | delete members[user.id]; 37 | }; 38 | 39 | // Получить информацию по комнате 40 | const getChatRoomInfo = () => ({ 41 | name, 42 | image, 43 | numMembers: members.size, 44 | }); 45 | 46 | return { 47 | broadcastMessage, 48 | addEntry, 49 | getChatHistory, 50 | addUser, 51 | removeUser, 52 | getChatRoomInfo, 53 | }; 54 | }; 55 | 56 | module.exports = createChatRoom; 57 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/controller/chat/index.js: -------------------------------------------------------------------------------- 1 | const createSocket = require('socket.io'); 2 | const domain = require('../../domain'); 3 | 4 | const {clientManager, chatRoomManager, getChatHandlers} = domain.chatAPI; 5 | 6 | const initChat = (server) => { 7 | // Создаем соккет 8 | const socketIo = createSocket(server); 9 | 10 | // Подписываемся на соединение к сокету 11 | socketIo.on('connection', (client) => { 12 | // Создаем обработчики событий для чата 13 | const { 14 | handleRegister, 15 | handleJoin, 16 | handleLeave, 17 | handleMessage, 18 | handleGetChatRooms, 19 | handleGetAvailableUsers, 20 | handleDisconnect, 21 | } = getChatHandlers(client, clientManager, chatRoomManager); 22 | 23 | console.log('client connected...', client.id); 24 | clientManager.addClient(client); 25 | 26 | // подписываемся на все события чата 27 | client 28 | .on('register', handleRegister) 29 | .on('join', handleJoin) 30 | .on('leave', handleLeave) 31 | .on('message', handleMessage) 32 | .on('chatrooms', handleGetChatRooms) 33 | .on('availableUsers', handleGetAvailableUsers) 34 | .on('disconnect', () => { 35 | console.log('client disconnect...', client.id); 36 | handleDisconnect(); 37 | }) 38 | .on('error', (err) => { 39 | console.log('received error from client:', client.id); 40 | console.log(err); 41 | }); 42 | }); 43 | }; 44 | 45 | module.exports = initChat; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/chat/init-chat.js: -------------------------------------------------------------------------------- 1 | const createSocket = require('socket.io'); 2 | const clientManager = require('./client-manager'); 3 | const chatRoomManager = require('./chatroom-manager'); 4 | const getChatHandlers = require('./handlers'); 5 | 6 | const initChat = (server) => { 7 | // Создаем соккет 8 | const socketIo = createSocket(server); 9 | 10 | // Подписываемся на соединение к сокету 11 | socketIo.on('connection', (client) => { 12 | // Создаем обработчики событий для чата 13 | const { 14 | handleRegister, 15 | handleJoin, 16 | handleLeave, 17 | handleMessage, 18 | handleGetChatRooms, 19 | handleGetAvailableUsers, 20 | handleDisconnect, 21 | } = getChatHandlers(client, clientManager, chatRoomManager); 22 | 23 | console.log('client connected...', client.id); 24 | clientManager.addClient(client); 25 | 26 | // подписываемся на все события чата 27 | client 28 | .on('register', handleRegister) 29 | .on('join', handleJoin) 30 | .on('leave', handleLeave) 31 | .on('message', handleMessage) 32 | .on('chatrooms', handleGetChatRooms) 33 | .on('availableUsers', handleGetAvailableUsers) 34 | .on('disconnect', () => { 35 | console.log('client disconnect...', client.id); 36 | handleDisconnect(); 37 | }) 38 | .on('error', (err) => { 39 | console.log('received error from client:', client.id); 40 | console.log(err); 41 | }); 42 | }); 43 | }; 44 | 45 | module.exports = initChat; -------------------------------------------------------------------------------- /lesson-2/demo/src/routes/user/create-user.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const util = require('util'); 4 | 5 | const usersFolder = path.resolve(__dirname, '../../../', 'data/users'); 6 | 7 | const writeFile = util.promisify(fs.writeFile); 8 | 9 | const saveNewUser = (fileName, data) => { 10 | const src = path.resolve(usersFolder, fileName + '.json'); 11 | const dataStr = JSON.stringify(data); 12 | 13 | // returning promise 14 | return writeFile(src, dataStr); 15 | }; 16 | 17 | const createUser = (request, response) => { 18 | let body = []; 19 | 20 | const handleDataLoad = () => { 21 | const data = Buffer.concat(body).toString(); 22 | 23 | var fileStream = fs.createWriteStream(path.join(__dirname, 'user-image.json')); 24 | fileStream.write(body.toString()); 25 | fileStream.end(); 26 | 27 | fileStream.on('data', (chunk) => { 28 | console.log('chunk', chunk); 29 | }); 30 | 31 | const userData = Object.assign({}, JSON.parse(data), { id: Date.now() }); 32 | 33 | const fileName = userData.userName.toLowerCase() + userData.id; 34 | 35 | const sendResponse = () => { 36 | response.writeHead(200, {"Content-Type": "application/json"}); 37 | response.write(JSON.stringify(userData)); 38 | response.end(); 39 | }; 40 | 41 | saveNewUser(fileName, userData) 42 | .then(sendResponse) 43 | .catch(console.log); 44 | }; 45 | 46 | request 47 | .on('data', (chunk) => { 48 | body.push(chunk); 49 | }) 50 | .on('end', handleDataLoad); 51 | }; 52 | 53 | module.exports = createUser; 54 | -------------------------------------------------------------------------------- /lesson-1/screencast-materials/http-module/http-server.js: -------------------------------------------------------------------------------- 1 | // http.createServer - метод для создания веб сервера на node js https://nodejs.org/api/http.html#http_http_createserver_options_requestlistener 2 | // http incoming message - обьект 'request' что приходит в коллбек http.createServer https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_incomingmessage 3 | // http server response - обьект 'response' что приходит 2м параметров в http.createServer https://nodejs.org/dist/latest-v10.x/docs/api/http.html#http_class_http_serverresponse 4 | 5 | const http = require('http'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | 10 | const server = http.createServer((request, response) => { 11 | 12 | console.log(request.url); 13 | 14 | if (request.url.includes('api')) { 15 | 16 | if (request.url.includes('products')) { 17 | const productFilePath = path.join(__dirname, 'products.json'); 18 | const products = fs.readFileSync(productFilePath); 19 | 20 | response.writeHead(200, {'content-type': 'application/json'}); 21 | response.write(products); 22 | response.end(); 23 | return; 24 | } 25 | } 26 | 27 | if (request.url.includes('text')) { 28 | response.write('Hello world'); 29 | response.end(); 30 | return; 31 | } 32 | 33 | const productPageFilePath = path.join(__dirname, 'product-page.html'); 34 | const productsHTML = fs.readFileSync(productPageFilePath); 35 | 36 | response.writeHead(200, {'content-type': 'text/html'}); 37 | response.write(productsHTML); 38 | response.end(); 39 | }); 40 | 41 | 42 | server.listen(3000); 43 | 44 | console.log('Server is running on port 3000'); -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/chat/client-manager.js: -------------------------------------------------------------------------------- 1 | // Шаблон пользователей 2 | const userTemplates = require('./templates/users'); 3 | 4 | // Все доступные устройства с пользователями что есть в чате 5 | const clients = {}; 6 | 7 | // Добавить устройство 8 | const addClient = (client) => { 9 | console.log('Client added', client.id); 10 | 11 | clients[client.id] = { client }; 12 | }; 13 | 14 | // Зарегистрировать пользователя 15 | const registerClient = (client, user) => { 16 | // client - устройство/клиент 17 | // user - пользователь 18 | console.log('Client registered', client.id); 19 | 20 | clients[client.id] = { client, user }; 21 | }; 22 | 23 | const removeClient = (client) => { 24 | console.log('Client removed'); 25 | 26 | delete clients[client.id]; 27 | }; 28 | 29 | // Взять всех свободных пользователей которых еще нет в чате из шаблона 30 | const getAvailableUsers = () => { 31 | const allClients = Object.values(clients); 32 | 33 | const uniqueUsers = new Set( 34 | allClients 35 | .filter(c => c.user) 36 | .map(c => c.user.name), 37 | ); 38 | 39 | return userTemplates.filter(u => !uniqueUsers.has(u.name)); 40 | }; 41 | 42 | const isUserAvailable = (userName) => { 43 | return getAvailableUsers().some(u => u.name === userName); 44 | }; 45 | 46 | // Взять пользователя из шаблона по id устройства 47 | const getUserByName = (userName) => { 48 | return userTemplates.find(u => u.name === userName); 49 | }; 50 | 51 | // Взять пользователя по id устройства 52 | const getUserByClientId = (clientId) => { 53 | const client = clients[clientId] || {}; 54 | 55 | return client.user; 56 | }; 57 | 58 | 59 | 60 | module.exports = { 61 | addClient, 62 | registerClient, 63 | removeClient, 64 | getAvailableUsers, 65 | isUserAvailable, 66 | getUserByName, 67 | getUserByClientId, 68 | }; 69 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/chat/client-manager.js: -------------------------------------------------------------------------------- 1 | // Шаблон пользователей 2 | const userTemplates = require('./templates/users'); 3 | 4 | // Все доступные устройства с пользователями что есть в чате 5 | const clients = {}; 6 | 7 | // Добавить устройство 8 | const addClient = (client) => { 9 | console.log('Client added', client.id); 10 | 11 | clients[client.id] = { client }; 12 | }; 13 | 14 | // Зарегистрировать пользователя 15 | const registerClient = (client, user) => { 16 | // client - устройство/клиент 17 | // users - пользователь 18 | console.log('Client registered', client.id); 19 | 20 | clients[client.id] = { client, user }; 21 | }; 22 | 23 | const removeClient = (client) => { 24 | console.log('Client removed'); 25 | 26 | delete clients[client.id]; 27 | }; 28 | 29 | // Взять всех свободных пользователей которых еще нет в чате из шаблона 30 | const getAvailableUsers = () => { 31 | const allClients = Object.values(clients); 32 | 33 | const uniqueUsers = new Set( 34 | allClients 35 | .filter(c => c.user) 36 | .map(c => c.user.name), 37 | ); 38 | 39 | return userTemplates.filter(u => !uniqueUsers.has(u.name)); 40 | }; 41 | 42 | const isUserAvailable = (userName) => { 43 | return getAvailableUsers().some(u => u.name === userName); 44 | }; 45 | 46 | // Взять пользователя из шаблона по id устройства 47 | const getUserByName = (userName) => { 48 | return userTemplates.find(u => u.name === userName); 49 | }; 50 | 51 | // Взять пользователя по id устройства 52 | const getUserByClientId = (clientId) => { 53 | const client = clients[clientId] || {}; 54 | 55 | return client.user; 56 | }; 57 | 58 | 59 | 60 | module.exports = { 61 | addClient, 62 | registerClient, 63 | removeClient, 64 | getAvailableUsers, 65 | isUserAvailable, 66 | getUserByName, 67 | getUserByClientId, 68 | }; 69 | -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/UserSelection.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Dialog from 'material-ui/Dialog'; 3 | import FlatButton from 'material-ui/FlatButton'; 4 | import { List, ListItem } from 'material-ui/List'; 5 | import Avatar from 'material-ui/Avatar'; 6 | 7 | import Loader from './Loader' 8 | 9 | export default class UserSelection extends React.Component { 10 | constructor(props) { 11 | super(props) 12 | this.state = { 13 | availableUsers: null 14 | } 15 | 16 | this.handleSelection = this.handleSelection.bind(this) 17 | this.renderUserItems = this.renderUserItems.bind(this) 18 | 19 | this.props.getAvailableUsers((err, availableUsers) => { 20 | this.setState({ availableUsers }) 21 | }) 22 | } 23 | 24 | handleSelection(selectedUser) { 25 | this.props.register(selectedUser.name) 26 | } 27 | 28 | renderUserItems() { 29 | return this.state.availableUsers.map(user => ( 30 | this.handleSelection(user)} 32 | primaryText={user.name} 33 | secondaryText={user.statusText} 34 | leftAvatar={} 35 | /> 36 | )) 37 | } 38 | 39 | render() { 40 | const actions = [ 41 | 46 | ] 47 | 48 | return ( 49 | 56 | { 57 | !this.state.availableUsers 58 | ? 59 | : ( 60 | 61 | { this.renderUserItems() } 62 | 63 | ) 64 | } 65 | 66 | ) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lesson-6/demo/server/src/controller/image/save-image-multipart.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const util = require('util'); 5 | 6 | const renameFile = util.promisify(fs.rename); 7 | 8 | const TEMP_IMAGE_FOLDER = path.join(__dirname, '../../../', 'assets'); 9 | const USER_IMAGE_FOLDER = path.join(__dirname, '../../../', 'data', 'user-images'); 10 | 11 | const storage = multer.diskStorage({ 12 | // определяем папку куда сохранять временное изображение 13 | destination: (req, file, next) => { 14 | next(null, TEMP_IMAGE_FOLDER) 15 | }, 16 | // определяем имя файла 17 | filename: (req, file, next) => { 18 | next(null, file.originalname) 19 | } 20 | }); 21 | 22 | // Применяем настройки 23 | const upload = multer({ storage }); 24 | 25 | const moveImage = (fileObject, userId) => { 26 | // cоздаем папку для файлов пользователя 27 | const userImageFolderName = 'user-' + userId; 28 | const userImagePath = path.join(USER_IMAGE_FOLDER, userImageFolderName); 29 | 30 | if (!fs.existsSync(userImagePath)){ 31 | fs.mkdirSync(userImagePath); 32 | } 33 | 34 | const tempFilePath = path.join(TEMP_IMAGE_FOLDER, fileObject.originalname); 35 | const newFilePath = path.join(userImagePath, fileObject.originalname); 36 | 37 | return renameFile(tempFilePath, newFilePath).then(() => userImageFolderName); 38 | }; 39 | 40 | const saveImageMultipart = (req, res) => { 41 | // Берем файл 42 | const fileObject = req.file; 43 | 44 | // Берем другие данные что пришли 45 | const userId = req.body.userId; 46 | 47 | moveImage(fileObject, userId) 48 | .then(userImageFolderName => { 49 | res.json({ status: 'was saved in folder: ' + userImageFolderName }); 50 | }) 51 | 52 | }; 53 | 54 | // добавляем промежуточный обработчик для post-multipart запросов 55 | module.exports = () => [upload.single('file'), saveImageMultipart]; -------------------------------------------------------------------------------- /lesson-6/demo/server/src/routes/image/save-image-multipart.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const util = require('util'); 5 | 6 | const renameFile = util.promisify(fs.rename); 7 | 8 | const TEMP_IMAGE_FOLDER = path.join(__dirname, '../../../', 'assets'); 9 | const USER_IMAGE_FOLDER = path.join(__dirname, '../../../', 'data', 'user-images'); 10 | 11 | const storage = multer.diskStorage({ 12 | // определяем папку куда сохранять временное изображение 13 | destination: (req, file, next) => { 14 | next(null, TEMP_IMAGE_FOLDER) 15 | }, 16 | // определяем имя файла 17 | filename: (req, file, next) => { 18 | next(null, file.originalname) 19 | } 20 | }); 21 | 22 | // Применяем настройки 23 | const upload = multer({ storage }); 24 | 25 | const moveImage = (fileObject, userId) => { 26 | // cоздаем папку для файлов пользователя 27 | const userImageFolderName = 'user-' + userId; 28 | const userImagePath = path.join(USER_IMAGE_FOLDER, userImageFolderName); 29 | 30 | if (!fs.existsSync(userImagePath)){ 31 | fs.mkdirSync(userImagePath); 32 | } 33 | 34 | const tempFilePath = path.join(TEMP_IMAGE_FOLDER, fileObject.originalname); 35 | const newFilePath = path.join(userImagePath, fileObject.originalname); 36 | 37 | return renameFile(tempFilePath, newFilePath).then(() => userImageFolderName); 38 | }; 39 | 40 | const saveImageMultipart = (req, res) => { 41 | // Берем файл 42 | const fileObject = req.file; 43 | 44 | // Берем другие данные что пришли 45 | const userId = req.body.userId; 46 | 47 | moveImage(fileObject, userId) 48 | .then(userImageFolderName => { 49 | res.json({ status: 'was saved in folder: ' + userImageFolderName }); 50 | }) 51 | 52 | }; 53 | 54 | // добавляем промежуточный обработчик для post-multipart запросов 55 | module.exports = () => [upload.single('file'), saveImageMultipart]; -------------------------------------------------------------------------------- /lesson-5/demo/src/routes/image/save-image-multipart.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const util = require('util'); 5 | 6 | const renameFileAsync = util.promisify(fs.rename); 7 | 8 | const TEMP_IMAGE_FOLDER = path.join(__dirname, '../../../', 'assets'); 9 | const USER_IMAGE_FOLDER = path.join(__dirname, '../../../', 'data', 'user-images'); 10 | 11 | const storage = multer.diskStorage({ 12 | // определяем папку куда сохранять временное изображение 13 | destination: (req, file, next) => { 14 | next(null, TEMP_IMAGE_FOLDER) 15 | }, 16 | // определяем имя файла 17 | filename: (req, file, next) => { 18 | next(null, file.originalname) 19 | } 20 | }); 21 | 22 | // Применяем настройки 23 | const upload = multer({ storage }); 24 | 25 | const moveImage = (fileObject, userId) => { 26 | // cоздаем папку для файлов пользователя 27 | const userImageFolderName = 'user-' + userId; 28 | const userImagePath = path.join(USER_IMAGE_FOLDER, userImageFolderName); 29 | 30 | const directoryExists = fs.existsSync(userImagePath); 31 | 32 | if (!directoryExists){ 33 | fs.mkdirSync(userImagePath); 34 | } 35 | 36 | const tempFilePath = path.join(TEMP_IMAGE_FOLDER, fileObject.originalname); 37 | const newFilePath = path.join(userImagePath, fileObject.originalname); 38 | 39 | return renameFileAsync(tempFilePath, newFilePath) 40 | .then(() => userImageFolderName); 41 | }; 42 | 43 | const saveImageMultipart = (req, res) => { 44 | // Берем файл 45 | const fileObject = req.file; 46 | 47 | // Берем другие данные что пришли 48 | const userId = req.body.userId; 49 | 50 | moveImage(fileObject, userId) 51 | .then(userImageFolderName => { 52 | res.json({ status: 'was saved in folder: ' + userImageFolderName }); 53 | }) 54 | 55 | }; 56 | 57 | // добавляем промежуточный обработчик для post-multipart запросов 58 | module.exports = () => [upload.single('file'), saveImageMultipart]; -------------------------------------------------------------------------------- /lesson-1/screencast-materials/fs-module/demo-with-files.js: -------------------------------------------------------------------------------- 1 | // fs.readFile - для чтения файлов https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback 2 | // fs.writeFile - для записи файлов https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback 3 | // fs.unlink - для удаления файла/папке https://nodejs.org/api/fs.html#fs_fs_unlink_path_callback 4 | // fs.rename - для перемещения файла https://nodejs.org/docs/latest/api/fs.html#fs_fs_rename_oldpath_newpath_callback 5 | 6 | const fs = require('fs'); 7 | 8 | const productsToAdd = [ 9 | { 10 | "id": 19112836, 11 | "sku": 1120002, 12 | "name": "Крем-суп из тыквы", 13 | "description": "Портрет этой оранжевой похлебки украшает обложку книги «La Cuisine du Marché» Поля Бокюза. Бокюз, придумавший так называемую новую кухню, считал тыкву одной из основ этого миропорядка, а тыквенный суп — эдакой околоплодной водой гастрономии", 14 | "price": "80", 15 | "currency": "UAN", 16 | "creatorId": 1, 17 | "categories": ["soup"] 18 | }, 19 | { 20 | "id": 19112837, 21 | "sku": 1120002, 22 | "name": "Томатный магрибский суп", 23 | "description": "Томатный магрибский суп особенно распространен в Марокко и Тунисе. Он весьма прост в приготовлении и сам по себе легкий — в основе томаты и куриный бульон. Кроме них в супе только необходимые специи, мед и лимон, которые все вместе и передают тот самый восточный колорит. Вкус супа всецело зависит от качества томатов", 24 | "price": "100", 25 | "currency": "UAN", 26 | "creatorId": 1, 27 | "categories": ["soup"] 28 | } 29 | ]; 30 | 31 | const productsPath = 'local-database/input-products.json'; 32 | const newProductsPath = 'local-database-new/output-products.json'; 33 | 34 | // fs.readFile(productsPath, 'utf8', (err, data) => { 35 | // const products = JSON.parse(data); 36 | // 37 | // const newProducts = [...products, ...productsToAdd]; 38 | // 39 | // fs.writeFile(newProductsPath, JSON.stringify(newProducts), (err) => { 40 | // console.log('done'); 41 | // }) 42 | // 43 | // }); 44 | 45 | fs.rename(productsPath, newProductsPath, () => { 46 | console.log('done'); 47 | }); -------------------------------------------------------------------------------- /lesson-3/demo/src/routes/image/save-image-multipart.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const util = require('util'); 5 | 6 | const renameFile = util.promisify(fs.rename); 7 | 8 | const TEMPORARY_IMAGE_FOLDER = path.join(__dirname, '../../../', 'assets'); 9 | const USER_IMAGE_FOLDER = path.join(__dirname, '../../../', 'data', 'user-images'); 10 | 11 | const storage = multer.diskStorage({ 12 | // определяем временную папку куда сохранить изображение 13 | destination: (req, file, next) => { 14 | next(null, TEMPORARY_IMAGE_FOLDER) 15 | }, 16 | // определяем имя файла 17 | filename: (req, file, next) => { 18 | next(null, file.originalname) 19 | } 20 | }); 21 | 22 | // Применяем настройки 23 | const upload = multer(storage); 24 | 25 | const createUserFolder = (filePath) => { 26 | if (!fs.existsSync(filePath)){ 27 | fs.mkdirSync(filePath); 28 | } 29 | }; 30 | 31 | const moveImage = (fileObject, userId) => { 32 | // cоздаем папку для файлов пользователя 33 | const userImageFolderName = 'user-' + userId; 34 | const userImagePath = path.join(USER_IMAGE_FOLDER, userImageFolderName); 35 | 36 | createUserFolder(userImagePath); 37 | 38 | const pathToTemporaryImage = path.join(TEMPORARY_IMAGE_FOLDER, fileObject.originalname); 39 | const pathToRegularImage = path.join(userImagePath, fileObject.originalname); 40 | 41 | return renameFile(pathToTemporaryImage, pathToRegularImage) 42 | .then(() => { 43 | return userImageFolderName; 44 | }) 45 | .catch((error) => console.log(error)) 46 | }; 47 | 48 | const saveImageMultipart = (req, res) => { 49 | // Берем файл 50 | const fileObject = req.file; 51 | 52 | // Берем другие данные что пришли 53 | // const userId = req.body.userId; 54 | const userId = '1234'; 55 | 56 | moveImage(fileObject, userId) 57 | .then(userImageFolderName => { 58 | res.json({ status: 'was saved in folder: ' + userImageFolderName }); 59 | }); 60 | }; 61 | 62 | // добавляем промежуточный обработчик для post-multipart запросов 63 | module.exports = () => [upload.single('image'), saveImageMultipart]; -------------------------------------------------------------------------------- /lesson-1/demo/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.7.1", 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "basic-auth": { 7 | "version": "2.0.1", 8 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 9 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==" 10 | }, 11 | "debug": { 12 | "version": "2.6.9", 13 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 14 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" 15 | }, 16 | "depd": { 17 | "version": "1.1.2", 18 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 19 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 20 | }, 21 | "ee-first": { 22 | "version": "1.1.1", 23 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 24 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 25 | }, 26 | "morgan": { 27 | "version": "1.9.1", 28 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", 29 | "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==" 30 | }, 31 | "ms": { 32 | "version": "2.0.0", 33 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 34 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 35 | }, 36 | "on-finished": { 37 | "version": "2.3.0", 38 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 39 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=" 40 | }, 41 | "on-headers": { 42 | "version": "1.0.1", 43 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", 44 | "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" 45 | }, 46 | "safe-buffer": { 47 | "version": "5.1.2", 48 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 49 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/MainLayout.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import styled from 'styled-components'; 4 | import Avatar from 'material-ui/Avatar'; 5 | import FontIcon from 'material-ui/FontIcon'; 6 | 7 | import FullScreen from './FullScreen'; 8 | import Overlay from './Overlay'; 9 | 10 | const ContentWrapper = styled.div` 11 | position: relative; 12 | height: 100%; 13 | width: 100%; 14 | overflow: auto; 15 | z-index: 1; 16 | ` 17 | const Center = styled.div` 18 | position: relative; 19 | max-width: 1000px; 20 | margin: auto; 21 | padding: 40px 0; 22 | height: 100%; 23 | box-sizing: border-box; 24 | ` 25 | 26 | const Content = styled.div` 27 | position: relative; 28 | display: flex; 29 | flex-wrap: wrap; 30 | justify-content: space-between; 31 | margin: 0 20px; 32 | height: 100%; 33 | ` 34 | 35 | const BackgroundImage = styled.div` 36 | background: url(${props => props.src}) no-repeat center center fixed; 37 | background-size: cover; 38 | height: 100%; 39 | overflow: hidden; 40 | ` 41 | 42 | const AvatarWrapper = styled.div` 43 | cursor: pointer; 44 | display: flex; 45 | flex-direction: column; 46 | align-items: center; 47 | a { 48 | text-decoration: none; 49 | } 50 | img { 51 | box-shadow: rgba(255, 255, 255, 0.2) 0 0 10px 2px; 52 | } 53 | ` 54 | 55 | const Relative = styled.div` 56 | position: relative; 57 | ` 58 | 59 | const Sticky = styled.div` 60 | position: fixed; 61 | ` 62 | const UserName = styled.p` 63 | font-size: 24px; 64 | height: 27px; 65 | text-align: center; 66 | color: #fafafa; 67 | ` 68 | 69 | function renderAvatar(user) { 70 | const props = user 71 | ? { src: user.image } 72 | : { 73 | icon: 74 | 78 | {'perm_identity'} 79 | 80 | } 81 | 82 | return 83 | } 84 | 85 | function fullName(user) { 86 | return user ? `${user.name} ${user.lastName}` : 'Who are you?' 87 | } 88 | 89 | export default ({ children, user }) => ( 90 | 91 | 92 |
93 | 94 | 95 | 96 | 97 | 98 | { renderAvatar(user) } 99 | 100 | { fullName(user) } 101 | 102 | 103 | 104 | { children } 105 | 106 |
107 |
108 | 109 | 110 | 114 | 115 |
116 | ) 117 | -------------------------------------------------------------------------------- /lesson-8/README.md: -------------------------------------------------------------------------------- 1 | # Lesson 8 2 | 3 | - Дизайн гибкой архитектуры в node.js 4 | 5 | ## Дизайн чистой архитектуры в node.js 6 | 7 | Плохая архитектура характеризуется 2мя терминами: 8 | - **хрупкостью** приложение ломается в местах которые не связаны с вносимыми изменениями. 9 | - **жесткостью** для добавление даже тривиальной новой фичи приходится вносить очень много изменений во много модулей приложения 10 | 11 | Приложение становится похожим на стекло. Оно готово разбится при любом неудобном движении. 12 | 13 | ### Зачем делать "чистую" архитектуру 14 | 15 | Она нужна для того чтобы: 16 | 17 | - отделить бизнес логику от деталей реализации 18 | - быть независимыми от базы данных, фреймворка или библиотеки 19 | - использовать чистые функции где только можно 20 | - упростить тестирование проекта 21 | - сделать добавление новых фич очень простым 22 | - сделать перенос логики очень простым 23 | 24 | 25 | ### Луковая архитектура 26 | 27 | Хорошим примером гибкой архитектуры является **Onion architecture** (Луковая архитектура). 28 | 29 | 30 | 31 | Особенностью архитектуры является то, что она состоит из разных слоев логики и данных, которые похожи на слои лука. 32 | Зная что нужно сейчас сделать мы понимаем в каком слое мы должны писать определенную логику. 33 | 34 | 35 | ### Onion architecture в деталях 36 | 37 | 38 | 39 | Абстракции в примерах: 40 | 41 | **Core, ядро системы** 42 | 43 | - стоительные блоки с которых вы будете делать приложение 44 | - логика которая не зависит от конкретного приложения 45 | - в большинстве это чистые функции, которые получают определеннные данных и возвращают другие 46 | - в Core никогда не должно быть импортов методов базы данных либо же request, response 47 | - Core не знает о других слоях вообще 48 | 49 | **Domain, доменный слой** 50 | - в этом слое находится логика вашего приложения 51 | - использует фукцнии из Сore и связывает их в логику 52 | - в домене не иcпользуются методы express 53 | - в домене можно использовать DB 54 | - вся структура должна быть разделена по сущностям нашего приложения (users, products, orders) 55 | 56 | **API, Gateway** 57 | 58 | Все эти названия обозначают одно и тоже. Это фасад для работы с Domain и Core логикой вашего приложения 59 | 60 | - должен возввращать имутабельные обьекты (чтобы исключить возможность мутации их в других модулях) 61 | - может работать с Core и Domain модулями, но ничего не знает об Infrastructure 62 | 63 | Пример методов в API: 64 | 65 | * createOrder 66 | * addProductToCart 67 | * removeProductFromCart 68 | 69 | * createUser 70 | * login 71 | * logout 72 | 73 | 74 | **Infrastructure** 75 | 76 | Слой который работает с базой данных и express напрямую 77 | 78 | 79 | **Правило зависимости** 80 | 81 | Круги представляют различные области программного обеспечения. В общем, чем дальше, тем выше уровень программного обеспечения. Внешние круги - это механизмы. Внутренние круги - это политика. 82 | 83 | Главное правило, которое заставляет эту архитектуру работать, - это правило зависимости. Зависимости исходного кода могут указывать только внутрь круга, но не вне. 84 | Пример: модель не может импортировать в себя ничего из контроллера или сервиса. 85 | 86 | **Модули, функции, классы внутреннего круга не могут знать ничего о тех же сущностях внешнго круга**. 87 | 88 | Имя чего-либо, объявленного во внешнем круге, не должно упоминаться кодом во внутреннем круге. Это включает в себя, функции, классы. переменные или любой другой названный программный объект. 89 | 90 | Точно так же форматы данных (в нашем случае обьектов), используемые во внешнем круге, не должны использоваться внутренним кругом, особенно если эти форматы создаются структурой во внешнем круге. 91 | Мы не хотим, чтобы что-то во внешнем круге влияло на внутренние круги. 92 | 93 | 94 | [Статья о луковой архитектуре](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) 95 | 96 | -------------------------------------------------------------------------------- /z-demo-tel-bot-11/demo/src/modules/telegram-bot.js: -------------------------------------------------------------------------------- 1 | const TelegramBot = require('node-telegram-bot-api'); 2 | 3 | const token = '763007650:AAFyABbLrRplzWw24OGg5r0_auackn93QuE'; 4 | 5 | const START_CHAT = 'START_CHAT'; 6 | const FINISH_CHAT = 'FINISH_CHAT'; 7 | const DEFAULT = 'DEFAULT'; 8 | const DO_YOU_LOVE_ME = 'DO_YOU_LOVE_ME'; 9 | const CHOSE_JOY = 'CHOSE_JOY'; 10 | const THANK_YOU = 'THANK_YOU'; 11 | const REJECT = 'REJECT'; 12 | const GIVE_BEER = 'GIVE_BEER'; 13 | const REMIND_ABOUT_GIRL = 'REMIND_ABOUT_GIRL'; 14 | const OFFER_SOMETHING = 'OFFER_SOMETHING'; 15 | 16 | const getResponseKey = (message) => { 17 | // Give me some beer 18 | 19 | if (message.includes('hello')) return START_CHAT; 20 | if (message.includes('bye')) return FINISH_CHAT; 21 | if (message.match(/confess/)) return DO_YOU_LOVE_ME; 22 | if (message.includes('you are the bot of my life')) return THANK_YOU; 23 | if (message.includes('sorry there is another one')) return REJECT; 24 | if (message.match(/sudo/)) return GIVE_BEER; 25 | if (message.match(/beer/)) return REJECT; 26 | if (message.match(/ask/)) return OFFER_SOMETHING; 27 | if (message.match(/no,/)) return DO_YOU_LOVE_ME; 28 | if (message.match(/money/)) return REJECT; 29 | if (message.match(/girls/)) return REMIND_ABOUT_GIRL; 30 | if (message.match(/alcohol/)) return GIVE_BEER; 31 | 32 | return DEFAULT; 33 | }; 34 | 35 | const getResponseFunction = (actionKey, bot) => { 36 | const hideKeyboard = {reply_markup: JSON.stringify({ hide_keyboard: true })}; 37 | 38 | const actions = { 39 | [START_CHAT]: ({ firstName, lastName, chatId }) => { 40 | bot.sendMessage(chatId, `Hello ${ firstName } ${ lastName }, \u{1F63B}`); 41 | }, 42 | [FINISH_CHAT]: ({ firstName, lastName, chatId }) => { 43 | bot.sendMessage(chatId, `Bye ${ firstName } ${ lastName } \u{1F416}`); 44 | }, 45 | [DEFAULT]: ({ firstName, lastName, chatId }) => { 46 | bot.sendMessage(chatId, `I don't understand you \u{23F0}`); 47 | }, 48 | [THANK_YOU]: ({ firstName, lastName, chatId }) => { 49 | bot.sendMessage(chatId, `I love you too ${firstName} \u{2764}`, hideKeyboard ); 50 | }, 51 | [REJECT]: ({ firstName, lastName, chatId }) => { 52 | bot.sendMessage(chatId, `Go away ${firstName}`, hideKeyboard); 53 | }, 54 | [REMIND_ABOUT_GIRL]: ({ firstName, lastName, chatId }) => { 55 | bot.sendMessage(chatId, `Don't you love your girl, ${firstName}?`, hideKeyboard); 56 | }, 57 | [GIVE_BEER]: ({ firstName, lastName, chatId }) => { 58 | bot.sendMessage(chatId, `Here is your beer ${firstName}`, hideKeyboard); 59 | }, 60 | [OFFER_SOMETHING]: (userData, msg) => { 61 | const opts = { 62 | reply_to_message_id: msg.message_id, 63 | reply_markup: JSON.stringify({ 64 | keyboard: [ 65 | ['Money'], 66 | ['Girls'], 67 | ['Alcohol'], 68 | ] 69 | }) 70 | }; 71 | bot.sendMessage(msg.chat.id, 'What do you want?', opts); 72 | }, 73 | [DO_YOU_LOVE_ME]: (userData, msg) => { 74 | const opts = { 75 | reply_to_message_id: msg.message_id, 76 | reply_markup: JSON.stringify({ 77 | keyboard: [ 78 | ['Yes, you are the bot of my life'], 79 | ['No, sorry there is another one...'] 80 | ] 81 | }) 82 | }; 83 | bot.sendMessage(msg.chat.id, 'Do you love me?', opts); 84 | } 85 | }; 86 | 87 | return actions[actionKey] || actions[DEFAULT]; 88 | }; 89 | 90 | const startBot = () => { 91 | const bot = new TelegramBot(token, { polling: true }); 92 | 93 | bot.on('message', (msg) => { 94 | const chatId = msg.chat.id; 95 | const { first_name: firstName, last_name: lastName } = msg.from; 96 | 97 | const message = msg.text.toLowerCase(); 98 | const userData = { 99 | firstName, 100 | lastName, 101 | chatId 102 | }; 103 | 104 | const actionKey = getResponseKey(message); 105 | const respond = getResponseFunction(actionKey, bot); 106 | 107 | respond(userData, msg); 108 | }); 109 | 110 | }; 111 | 112 | module.exports = startBot; -------------------------------------------------------------------------------- /lesson-9/README.md: -------------------------------------------------------------------------------- 1 | # Lesson 9 2 | 3 | - Платформа Heroku 4 | - Деплой приложения на Heroku 5 | - Выгрузка файлов на Amazon S3 6 | 7 | ## Heroku 8 | 9 | Heroku - это отличная площадка для хостинга проектов. 10 | 11 | Для загрузки проекта heroku предоставляет удобные инструменты, на данный момент их 3 и это более чем достаточно. С двумя из трех многие давно знакомы, это GitHub и Dropbox. Третий инструмент Heroku Toolbelt, пожалуй, самый необходимый инструмент для тесной работы с платформой, позволяет создавать проекты, загружать исходный код, смотреть и настраивать конфиг, отдает логии и многое другое. 12 | 13 | GitHub и Dropbox являются больше менеджерами загрузки проектов, с их помощью можно загружать проект на heroku, но инструментов для управления они не предоставляют. Если плотно работаете с GitHub, то можете настроить автоматический деплой проекта на heroku. Загрузку из Dropbox можно сделать только из веб интерфейса (dashboard) проекта на вкладке Deploy. 14 | 15 | ### Дино контейнеры 16 | 17 | Пользуясь платформой вы часто сможете увидить такое слово как *dyno*. 18 | 19 | Это специальные изолированые контейнеры с линуксом в которые помещаются приложения. Так же это "строительные блоки" которые позволяют расширять приложения не прикладывая лишних усилий. 20 | 21 | [Статья о dynos](https://www.heroku.com/dynos) 22 | 23 | ### Ограничения 24 | 25 | Стоит сказать что платформа имеет ряд ограничений связаных как с особенностями платформы так и с бесплатным аккаунтом. 26 | 27 | Например для бесплатного акаунта доступно только 512мб оперативки. 28 | 29 | Проект погружается в "сон", если в течении часа к нему не было обращений. После обращения проект просыпается. Репозиторий не может превышать 1 Гб. 30 | 31 | [Список всех ограничений](https://devcenter.heroku.com/articles/limits) 32 | 33 | 34 | ## Деплой приложения 35 | 36 | Деплой приложения можно разделить на несколько этапов: 37 | 38 | ### Настройка приложения 39 | - Создание git репозитория с вашим проектом 40 | - Обьявление переменных в конфиге 41 | - Разделение конфига на приватный и публичный 42 | - Распаковка фронтенда в репозиторий 43 | 44 | 45 | ### Публикация приложения на heroku 46 | - установка heroku 47 | - создание проекта на heroku 48 | - публикация проекта на heroku 49 | 50 | [Инструкция на heroku](https://devcenter.heroku.com/articles/deploying-nodejs) 51 | 52 | 53 | ### Релизы 54 | 55 | В любом приложении есть такое понятие как релиз. По факту это перенос какой-либо версии вашего приложения на продакшн сервер. Обычно команда выбирает правила релизов которым следует каждый член команды. 56 | 57 | - continuous delivery 58 | - feature releases 59 | 60 | #### Continuous delivery (непрерывная доставка) 61 | Каждая фича/фикс выкатывается на продакшн сразу же как пройдет ревью. Все фичи выкатываются отдельно друго от друга. 62 | 63 | - разработчик заливает код в `staging` ветку 64 | - на сервере непрерывной интеграции изменения объединяются с основным кодом, выполняются юнит – тесты и всё заливается на стэйжинг среду; 65 | - в стэйжинг среде QA инженеры тестируют приложение; 66 | - разработчик заливает код в `master`ветку 67 | - разработчик деплоит код на продакшн (либо же автодеплой) 68 | 69 | #### feature releases 70 | Отдельная фича/фикс может быть выкачена в продакшн только с другими фичами и только в определенное время. 71 | 72 | Обычно релизы происходят через какой-то промежуток времени, который определяется бизнес требованиями (возможно командой). 73 | 74 | - разработчики заливает код в `develop` ветку 75 | - в `develop` ветке находятся все фичи подготовленые к релизу 76 | - в `develop` среде QA инженеры тестируют приложение; 77 | - когда подходит время релиза и все баги зафикшены `develop` ветка мерджится в `master` 78 | - разработчики деплоят `master` на продакшн (либо же автодеплой) 79 | 80 | [Git flow. Методология для работы с релизами](https://danielkummer.github.io/git-flow-cheatsheet/index.ru_RU.html) 81 | 82 | 83 | Если релиз был неудачный. Например, сразу после релиза на продакшене нашли багу. В таких случаях последний релиз откатывают на предыдущий. 84 | 85 | [Релизы на heroku](https://devcenter.heroku.com/articles/releases) 86 | 87 | 88 | ### Выгрузка файлов на Amazon S3 89 | 90 | Раздел в разработке ... 91 | 92 | [Статья о выгрузке]https://devcenter.heroku.com/articles/s3 -------------------------------------------------------------------------------- /lesson-6/demo/server/src/modules/chat/handlers.js: -------------------------------------------------------------------------------- 1 | const makeHandleEvent = (client, clientManager, chatRoomManager) => { 2 | // проверка на то выбрали ли мы пользователя 3 | const ensureUserSelected = (clientId) => { 4 | const user = clientManager.getUserByClientId(clientId); 5 | 6 | if (!user) { 7 | console.log('select user first'); 8 | return false; 9 | } 10 | 11 | return user; 12 | }; 13 | 14 | // проверка на то существует ли комната (чат рум) 15 | const ensureValidChatRoom = (chatRoomName) => { 16 | const chatRoom = chatRoomManager.getChatRoomByName(chatRoomName); 17 | 18 | if (!chatRoom) { 19 | console.log(`invalid chatRoom name: ${chatRoomName}`); 20 | return false; 21 | } 22 | 23 | return chatRoom; 24 | }; 25 | 26 | // сама проверка на чат рум и юзера 27 | const ensureValidChatRoomAndUserSelected = (chatRoomName) => 28 | new Promise((resolve, reject) => { 29 | const chatRoom = ensureValidChatRoom(chatRoomName); 30 | const user = ensureUserSelected(client.id); 31 | 32 | if (chatRoom && user) { 33 | resolve({chatRoom, user}); 34 | } 35 | 36 | reject(); 37 | }); 38 | 39 | // функция обработки событий со всеми проверками 40 | const handleEvent = (chatRoomName, createEntry) => ( 41 | // проверяем правильный ли чат рум и юзер передан с клиента 42 | ensureValidChatRoomAndUserSelected(chatRoomName) 43 | .then(({ chatRoom, user }) => { 44 | 45 | // Создание самой записи сообщения для чат румы 46 | const message = Object.assign({ user }, createEntry()); 47 | 48 | // Добавление записи в историю сообщений чат румы 49 | chatRoom.addEntry(message); 50 | 51 | const messageWithChat = Object.assign({chat: chatRoomName}, message ); 52 | 53 | // отсылаем сообщение всем остальным участникам чат рума 54 | chatRoom.broadcastMessage(messageWithChat); 55 | 56 | return chatRoom; 57 | }) 58 | ); 59 | 60 | return handleEvent; 61 | }; 62 | 63 | const getChatHandlers = (client, clientManager, chatRoomManager) => { 64 | // создаем обертку для функции чтобы проверить есть ли все данные для обработки 65 | const handleEvent = makeHandleEvent(client, clientManager, chatRoomManager); 66 | 67 | // обработчик на регистрацию клиента (устройства что подключилось к чату) 68 | const handleRegister = (userName, respondToClient) => { 69 | if (!clientManager.isUserAvailable(userName)) { 70 | return respondToClient('user is not available'); 71 | } 72 | 73 | const user = clientManager.getUserByName(userName); 74 | 75 | clientManager.registerClient(client, user); 76 | 77 | return respondToClient(null, user); 78 | }; 79 | 80 | // обработчик на добавления юзера в чат рум (но добавляем мы устройство-клиент, а не юзера) 81 | const handleJoin = (chatRoomName, respondToClient) => { 82 | // Создаем функцию что возвращает сообщение для чата, позже она будет передана в чат руму 83 | const createEntry = () => ({event: `joined ${chatRoomName}`}); 84 | 85 | handleEvent(chatRoomName, createEntry).then(function(chatRoom) { 86 | // добавление юзера в чат рум 87 | chatRoom.addUser(client); 88 | 89 | // отсылаем историю другим участникам чата 90 | respondToClient(null, chatRoom.getChatHistory()); 91 | }).catch(respondToClient); 92 | }; 93 | 94 | // обработчик на удаление юзера в чат рум 95 | const handleLeave = (chatRoomName, respondToClient) => { 96 | // Создаем функцию что возвращает сообщение для чата, позже она будет передана в чат руму 97 | const createEntry = () => ({event: `left ${chatRoomName}`}); 98 | 99 | handleEvent(chatRoomName, createEntry) 100 | .then(function(chatRoom) { 101 | // удаляем юзера с чат комнаты 102 | chatRoom.removeUser(client.id); 103 | 104 | respondToClient(null); 105 | }) 106 | .catch(respondToClient); 107 | }; 108 | 109 | // обработчик на сообщение в чат комнате 110 | const handleMessage = ({chatRoomName, message} = {}, respondToClient) => { 111 | // Создаем функцию что возвращает сообщение для чата, позже она будет передана в чат руму 112 | const createEntry = () => ({message}); 113 | 114 | handleEvent(chatRoomName, createEntry) 115 | .then(() => respondToClient(null)) 116 | .catch(respondToClient); 117 | }; 118 | 119 | // обработчик для получения списка всех доступных чат комнат 120 | const handleGetChatRooms = (respondToClient) => { 121 | return respondToClient(null, chatRoomManager.getAllCharRooms()); 122 | }; 123 | 124 | // обработчик для получения списка всех доступных юзеров 125 | const handleGetAvailableUsers = (respondToClient) => { 126 | return respondToClient(null, clientManager.getAvailableUsers()); 127 | }; 128 | 129 | const handleDisconnect = () => { 130 | // remove user profile 131 | clientManager.removeClient(client); 132 | // remove member from all chatRooms 133 | chatRoomManager.removeClient(client); 134 | }; 135 | 136 | return { 137 | handleRegister, 138 | handleJoin, 139 | handleLeave, 140 | handleMessage, 141 | handleGetChatRooms, 142 | handleGetAvailableUsers, 143 | handleDisconnect, 144 | }; 145 | }; 146 | 147 | module.exports = getChatHandlers; 148 | -------------------------------------------------------------------------------- /lesson-8/demo/server/src/domain/chat/handlers.js: -------------------------------------------------------------------------------- 1 | const makeHandleEvent = (client, clientManager, chatRoomManager) => { 2 | // проверка на то выбрали ли мы пользователя 3 | const ensureUserSelected = (clientId) => { 4 | const user = clientManager.getUserByClientId(clientId); 5 | 6 | if (!user) { 7 | console.log('select users first'); 8 | return false; 9 | } 10 | 11 | return user; 12 | }; 13 | 14 | // проверка на то существует ли комната (чат рум) 15 | const ensureValidChatRoom = (chatRoomName) => { 16 | const chatRoom = chatRoomManager.getChatRoomByName(chatRoomName); 17 | 18 | if (!chatRoom) { 19 | console.log(`invalid chatRoom name: ${chatRoomName}`); 20 | return false; 21 | } 22 | 23 | return chatRoom; 24 | }; 25 | 26 | // сама проверка на чат рум и юзера 27 | const ensureValidChatRoomAndUserSelected = (chatRoomName) => 28 | new Promise((resolve, reject) => { 29 | const chatRoom = ensureValidChatRoom(chatRoomName); 30 | const user = ensureUserSelected(client.id); 31 | 32 | if (chatRoom && user) { 33 | resolve({chatRoom, user}); 34 | } 35 | 36 | reject(); 37 | }); 38 | 39 | // функция обработки событий со всеми проверками 40 | const handleEvent = (chatRoomName, createEntry) => ( 41 | // проверяем правильный ли чат рум и юзер передан с клиента 42 | ensureValidChatRoomAndUserSelected(chatRoomName) 43 | .then(({ chatRoom, user }) => { 44 | 45 | // Создание самой записи сообщения для чат румы 46 | const message = Object.assign({ user }, createEntry()); 47 | 48 | // Добавление записи в историю сообщений чат румы 49 | chatRoom.addEntry(message); 50 | 51 | const messageWithChat = Object.assign({chat: chatRoomName}, message ); 52 | 53 | // отсылаем сообщение всем остальным участникам чат рума 54 | chatRoom.broadcastMessage(messageWithChat); 55 | 56 | return chatRoom; 57 | }) 58 | ); 59 | 60 | return handleEvent; 61 | }; 62 | 63 | const getChatHandlers = (client, clientManager, chatRoomManager) => { 64 | // создаем обертку для функции чтобы проверить есть ли все данные для обработки 65 | const handleEvent = makeHandleEvent(client, clientManager, chatRoomManager); 66 | 67 | // обработчик на регистрацию клиента (устройства что подключилось к чату) 68 | const handleRegister = (userName, respondToClient) => { 69 | if (!clientManager.isUserAvailable(userName)) { 70 | return respondToClient('users is not available'); 71 | } 72 | 73 | const user = clientManager.getUserByName(userName); 74 | 75 | clientManager.registerClient(client, user); 76 | 77 | return respondToClient(null, user); 78 | }; 79 | 80 | // обработчик на добавления юзера в чат рум (но добавляем мы устройство-клиент, а не юзера) 81 | const handleJoin = (chatRoomName, respondToClient) => { 82 | // Создаем функцию что возвращает сообщение для чата, позже она будет передана в чат руму 83 | const createEntry = () => ({event: `joined ${chatRoomName}`}); 84 | 85 | handleEvent(chatRoomName, createEntry).then(function(chatRoom) { 86 | // добавление юзера в чат рум 87 | chatRoom.addUser(client); 88 | 89 | // отсылаем историю другим участникам чата 90 | respondToClient(null, chatRoom.getChatHistory()); 91 | }).catch(respondToClient); 92 | }; 93 | 94 | // обработчик на удаление юзера в чат рум 95 | const handleLeave = (chatRoomName, respondToClient) => { 96 | // Создаем функцию что возвращает сообщение для чата, позже она будет передана в чат руму 97 | const createEntry = () => ({event: `left ${chatRoomName}`}); 98 | 99 | handleEvent(chatRoomName, createEntry) 100 | .then(function(chatRoom) { 101 | // удаляем юзера с чат комнаты 102 | chatRoom.removeUser(client.id); 103 | 104 | respondToClient(null); 105 | }) 106 | .catch(respondToClient); 107 | }; 108 | 109 | // обработчик на сообщение в чат комнате 110 | const handleMessage = ({chatRoomName, message} = {}, respondToClient) => { 111 | // Создаем функцию что возвращает сообщение для чата, позже она будет передана в чат руму 112 | const createEntry = () => ({message}); 113 | 114 | handleEvent(chatRoomName, createEntry) 115 | .then(() => respondToClient(null)) 116 | .catch(respondToClient); 117 | }; 118 | 119 | // обработчик для получения списка всех доступных чат комнат 120 | const handleGetChatRooms = (respondToClient) => { 121 | return respondToClient(null, chatRoomManager.getAllCharRooms()); 122 | }; 123 | 124 | // обработчик для получения списка всех доступных юзеров 125 | const handleGetAvailableUsers = (respondToClient) => { 126 | return respondToClient(null, clientManager.getAvailableUsers()); 127 | }; 128 | 129 | const handleDisconnect = () => { 130 | // remove users profile 131 | clientManager.removeClient(client); 132 | // remove member from all chatRooms 133 | chatRoomManager.removeClient(client); 134 | }; 135 | 136 | return { 137 | handleRegister, 138 | handleJoin, 139 | handleLeave, 140 | handleMessage, 141 | handleGetChatRooms, 142 | handleGetAvailableUsers, 143 | handleDisconnect, 144 | }; 145 | }; 146 | 147 | module.exports = getChatHandlers; 148 | -------------------------------------------------------------------------------- /lesson-7/README.md: -------------------------------------------------------------------------------- 1 | # Lesson 7 2 | 3 | - Авторизация с помощью Json Web Token (JWT) 4 | 5 | ## Авторизация с помощью Json Web Token (JWT) 6 | 7 | Аутентификация - проверка подлинности пользователя путём сравнения введённого им логина/пароля с данными сохранёнными в базе данных. 8 | 9 | Авторизация - проверка прав пользователя на доступ к определенным ресурсам. 10 | 11 | 12 | Все пользователи вашего сайта или приложения имеют абсолютно разные права доступа к нему. Например: модераторы сайта которые вносят новости и простые пользователи. 13 | Либо же пользователи что имеют платный аккаунт и те, что имеют бесплатный. 14 | 15 | В обоих случаях нужно каким-то образом разграничивать права этих пользователей. 16 | 17 | Для того, чтобы пользователь мог авторизоваться в системе, у него, естественно, должна быть учётная запись в этой самой системе. Следовательно, ему нужно предоставить возможность эту учётную запись каким-то образом создать. 18 | Но здесь есть пара нюансов. 19 | Как правило, учётные данные пользователя состоят из традиционных логина и пароля (ну и необозримого количества всяких необязательных полей на вкус разработчика). 20 | 21 | Пароли стоит хранить в шифрованном виде, для того чтобы их не смогли использовать злоумышленники. Еще более безопасный способ хранения - хеш. Это набор символов в который закодировано ваше сообщение. Раскодировать его можно лишь с помощью специального ключа. 22 | 23 | Даже получив в своё распоряжение хеши, злоумышленник не сможет восстановить пароли, а, следовательно, авторизоваться в системе, используя учётную запись, данные которой получил в своё распоряжение. 24 | 25 | #### Как происходит создание Json Web Token 26 | 27 | - Получаем пароль от пользователя 28 | - Генерируем хеш 29 | - Записываем хеш 30 | - При авторизации пользователь присылает нам логин и пароль, мы ищем его учётную запись по логину, хешируем присланный пароль, сверяем полученный хеш с тем, что записан в учётной записи 31 | - Высылаем пользователю кодированный веб-токен 32 | - При дальнейших действиях пользователя в системе проверяем веб-токен 33 | 34 | Можно еще например добавить время устаревания веб-токена, проверку IP. Но базовая схема именно такова. 35 | 36 | 37 | [О Json Web Token](http://whiteshieldsoftware.blogspot.com/2016/06/expressjs-user-login-and-registration.html) 38 | 39 | 40 | ## Домашнее задание 41 | 42 | 1. Добавить авторизацию для пользователей 43 | 44 | **Логин** 45 | - Добавить роут `POST auth/login` 46 | - В запросе `POST auth/login` указать данные пользователя (`username/email`, `password`) 47 | - В контроллере нужно создать JWT token и отправить его на клиент как в этом демо 48 | - На фронтенде нужно будеть этот токен добавить в хедеры (в формате `x-auth-token: 'Bearer '`) к каждому запросу что будет отправлятся на наш сервер. Этот шаг вы сделаете в `react` курсе 49 | - Добавить проверку на наличие токена ко всем роутам в приложении кроме `auth/login`, `auth/register` 50 | 51 | **Логаут** 52 | - Добавить роут `GET auth/logout` 53 | - В контроллере пока что ничего делать не нужно 54 | 55 | **Получение текущего пользователя** 56 | - Добавить роут `GET auth/сurrent` 57 | - В контроллере проверить токен и отправить данные этого же юзера с DB 58 | 59 | **Регистрация текущего пользователя** 60 | - Заменить роут `POST /signup` на `POST auth/register` 61 | - Логику создания юзера оставить той же 62 | 63 | 2. Добавить ингридиенты для товаров 64 | - Сделать новую коллекцию `ingredients` в DB 65 | ``` 66 | { 67 | "name": "tomato", 68 | "description": "Some vegitable", 69 | } 70 | ``` 71 | - Добавить в коллекцию инредиентов какие-то данные 72 | - К существующим продуктам добавить свойство `ingredients: [{type: , ref: ''}, {type: , ref: ''}]` 73 | - При добавлении свойтсва руководствоваться [вот этой инструкцией](https://mongoosejs.com/docs/populate.html#saving-refs) 74 | - Когда будете доставать `product` из DB нужно использовать функцию `.populate()` чтобы достать из DB и продукт, и ингредиенты ([документация](https://mongoosejs.com/docs/populate.html#population)) 75 | 76 | 3. Добавить комментарии к товару 77 | - Сделать новую коллекцию `сomments` в DB 78 | ``` 79 | { 80 | "product": "", 81 | "author": "", 82 | "text": "This pizza was the best", 83 | "mark": 5, 84 | } 85 | ``` 86 | Поле `mark` - это оценка товару, которую будет ставить пользователь. От 1 до 5. 87 | 88 | **Получение коментария** 89 | - сделать роут `GET comments/?productId="v123dsagasdg"` 90 | - в ответе нужно прислать массив с комментариями к указанному товару 91 | ``` 92 | { 93 | "status": "success", 94 | "сomments": [{ comment1 }, { comment2 }, { comment3 }] 95 | } 96 | ``` 97 | - если комментарием нет - то отправлять 98 | ``` 99 | { 100 | "status": "success", 101 | "сomments": [] 102 | } 103 | ``` 104 | 105 | **Создание коментария** 106 | - сделать роут `POST comments` 107 | - в запросе слать 108 | ``` 109 | { 110 | "product": "", 111 | "author": "", 112 | "text": "This pizza was the best", 113 | "mark": 4, 114 | } 115 | ``` 116 | - сохранить данные в DB 117 | 118 | -------------------------------------------------------------------------------- /lesson-6/README.md: -------------------------------------------------------------------------------- 1 | # Lesson 6 2 | 3 | - Websocket vs HTTP 4 | - socket.io 5 | - Чат 6 | 7 | ## Websocket 8 | 9 | WebSocket — протокол дуплексной связи (может передавать и принимать одновременно) поверх TCP-соединения, предназначенный для обмена сообщениями между браузером и веб-сервером в режиме реального времени. 10 | Веб-сокеты, в отличие от HTTP, позволяют работать с двунаправленным потоком данных, что делает эту технологию совершенно уникальной. 11 | 12 | Чем же эта технология отличается от HTTP? 13 | 14 | - В HTTP 1.1 (используется почти везде на данный момент) единственный вариант получить что-то от сервера - это отправить на него запрос. Для каждого запроса создается одно подключение к серверу. В одно время может быть только 6 одновременных подключений к одному домену. И это самая важная особенность. 15 | 16 | - В HTTP 2.0 (новый стандарт) появилась технология Server Push и Server Side Events, которая позволяет передавать данные с сервера на клиент и наоборот. Новая версия HTTP протокола может составить конкуренцию вебсокетам, но на данный момент она не так широко используется. 17 | 18 | 19 | Бывает много ситуаций когда нам нужно получить какие-то данные из сервера, которые от нас не зависят. Например сообщение от другого пользователя, либо же сообщение что на сервере закончилась обработка большого файла или еще что-либо. 20 | 21 | Единственный способ что позволяет нам сделать такое в HTTP 1.1 версии - это полинг. Другими словами "опрос" сервера, отправка запросов через определенный интервал с надеждой что сервер уже имеет данные что нам нужны. 22 | 23 | ###Пример HTTP pooling 24 | 25 | 26 | 27 | **Возможная реализация полинга** 28 | 29 | ``` 30 | (() => { 31 | const interval = 2000; 32 | 33 | const poll = () => { 34 | setTimeout(function(){ 35 | $.ajax({ 36 | url: 'https://api.example.com/endpoint', 37 | success: function(data) { 38 | 39 | if (!data) { 40 | // Рекурсивно выполняем следующий запрос 41 | poll(); 42 | } 43 | // Делаем что-то с `data` 44 | 45 | }, 46 | dataType: 'json' 47 | }); 48 | }, interval); 49 | } 50 | })(); 51 | ``` 52 | 53 | ###Пример websocket подключения 54 | 55 | 56 | 57 | Веб-сокетам же для ответа не нужны повторяющиеся запросы. Достаточно выполнить один запрос и ждать отклика. Вы можете просто слушать сервер, который будет отправлять вам сообщения по мере готовности. 58 | 59 | Веб-сокеты можно использовать для 60 | 61 | - приложения реального времени; 62 | - чат-приложения; 63 | - IoT-приложения; 64 | - многопользовательские игры. 65 | 66 | ### Сложности в использовании websocket подключения 67 | 68 | - с помощью websocket вы не сможете реализовать REST API для других клиентов. Вебсокет не поддерживает CORS. 69 | 70 | #### Примеры 71 | 72 | **Client** 73 | 74 | ``` 75 | 76 | 77 | 78 | Пример чата с веб-сокетом 79 | 80 | 81 | 90 | 91 | 92 | ``` 93 | 94 | **Server** 95 | 96 | ``` 97 | const WebSocket = require('ws'); 98 | 99 | // создаём новый websocket-сервер 100 | const wss = new WebSocket.Server({ 101 | port: 8080 102 | }); 103 | 104 | // отправляем клиентам, когда функция clientValidator возвращает true. this — это wss. 105 | wss.broadcast = function(data, clientValidator = () => true) { 106 | this.clients.forEach(client => { 107 | if (clientValidator(client)) { 108 | client.send(data); 109 | } 110 | }); 111 | } 112 | 113 | wss.on("connection", ws => { 114 | // событие будет вызвано, когда клиент отправит сообщение 115 | ws.on('message', message => { 116 | // отправляем сообщение всем, кроме автора 117 | wss.broadcast(message, client => client !== ws); 118 | }); 119 | }); 120 | ``` 121 | 122 | - [Статья о вебсокетах](https://tproger.ru/translations/what-are-web-sockets/) 123 | - [Статья об HTTP2 server push & server side events](https://habr.com/company/ruvds/blog/342346/) 124 | 125 | 126 | ### socket.io 127 | 128 | Socket.IO это библиотека что предоставляет удобную комуникацию клиента с сервером посредством передачи сообщений. Работает на websocket подключении. 129 | 130 | В библиотеку входит: 131 | 132 | - Node.js сервер 133 | - Javascript библиотека для клиента 134 | 135 | Кроме того, библиотека предоставляет такие функции как: 136 | - Переподключение в случае потери соединения (например пропал интернет). Клиент будет постоянно пытаться повторно подключиться пока сервер не будет доступен снова. 137 | - Обнаружение разъединения с сервером/клиентом. Механизм позволяет как серверу, так и клиенту узнать если другой не отвечает. 138 | - Возможность передачи файлов (Binary data) ArrayBuffer и Blob в браузере и Node.js 139 | - Поддержка мультиплексирования (создание нескольких неймспейсов) 140 | - Создание "комнат". В пределах каждого неймспейса вы можете определить произвольные каналы, называемые «Комнаты». К ним могут присоединиться сокеты. Затем вы можете транслировать сообщения любую комнату к которой присоединился сокет. Эта функция может быть полезнаой для отправки уведомлений группе пользователей или конкретному пользователю подключенному к нескольким устройствам. 141 | 142 | Пример: 143 | 144 | ``` 145 | io.on('connection', function(socket){ 146 | socket.emit('request', /* */); // emit an event to the socket 147 | io.emit('broadcast', /* */); // emit an event to all connected sockets 148 | socket.on('reply', function(){ /* */ }); // listen to the event 149 | }); 150 | ``` 151 | 152 | - [Документация](https://socket.io/docs/) 153 | -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/Root.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {BrowserRouter, Route, Switch, Redirect} from 'react-router-dom'; 3 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 4 | 5 | import MainLayout from './MainLayout'; 6 | import Home from './Home'; 7 | import Loader from './Loader'; 8 | import UserSelection from './UserSelection'; 9 | import Chatroom from './Chatroom'; 10 | import getChatHandlers from './socket'; 11 | 12 | export default class Root extends React.Component { 13 | constructor(props, context) { 14 | super(props, context); 15 | 16 | this.state = { 17 | user: null, 18 | isRegisterInProcess: false, 19 | client: getChatHandlers(), 20 | chatrooms: null, 21 | }; 22 | 23 | this.onEnterChatroom = this.onEnterChatroom.bind(this); 24 | this.onLeaveChatroom = this.onLeaveChatroom.bind(this); 25 | this.getChatrooms = this.getChatrooms.bind(this); 26 | this.register = this.register.bind(this); 27 | this.renderUserSelectionOrRedirect = this.renderUserSelectionOrRedirect.bind( 28 | this); 29 | 30 | this.getChatrooms(); 31 | } 32 | 33 | onEnterChatroom(chatroomName, onNoUserSelected, onEnterSuccess) { 34 | if (!this.state.user) 35 | return onNoUserSelected(); 36 | 37 | return this.state.client.join(chatroomName, (err, chatHistory) => { 38 | if (err) 39 | return console.error(err); 40 | return onEnterSuccess(chatHistory); 41 | }); 42 | } 43 | 44 | onLeaveChatroom(chatroomName, onLeaveSuccess) { 45 | this.state.client.leave(chatroomName, (err) => { 46 | if (err) 47 | return console.error(err); 48 | return onLeaveSuccess(); 49 | }); 50 | } 51 | 52 | getChatrooms() { 53 | this.state.client.getChatrooms((err, chatrooms) => { 54 | this.setState({chatrooms}); 55 | }); 56 | } 57 | 58 | register(name) { 59 | const onRegisterResponse = user => this.setState( 60 | {isRegisterInProcess: false, user}); 61 | this.setState({isRegisterInProcess: true}); 62 | this.state.client.register(name, (err, user) => { 63 | if (err) return onRegisterResponse(null); 64 | return onRegisterResponse(user); 65 | }); 66 | } 67 | 68 | renderUserSelectionOrRedirect(renderUserSelection) { 69 | if (this.state.user) { 70 | return ; 71 | } 72 | 73 | return this.state.isRegisterInProcess 74 | ? 75 | : renderUserSelection(); 76 | } 77 | 78 | renderChatroomOrRedirect(chatroom, {history}) { 79 | if (!this.state.user) { 80 | return ; 81 | } 82 | 83 | const {chatHistory} = history.location.state; 84 | 85 | return ( 86 | this.onLeaveChatroom( 92 | chatroom.name, 93 | () => history.push('/'), 94 | ) 95 | } 96 | onSendMessage={ 97 | (message, cb) => this.state.client.message( 98 | chatroom.name, 99 | message, 100 | cb, 101 | ) 102 | } 103 | registerHandler={this.state.client.registerHandler} 104 | unregisterHandler={this.state.client.unregisterHandler} 105 | /> 106 | ); 107 | } 108 | 109 | render() { 110 | return ( 111 | 112 | 113 | 116 | { 117 | !this.state.chatrooms 118 | ? 119 | : ( 120 | 121 | ( 126 | props.history.push('/user')} 130 | onEnterChatroom={ 131 | chatroomName => this.onEnterChatroom( 132 | chatroomName, 133 | () => props.history.push('/user'), 134 | chatHistory => props.history.push({ 135 | pathname: chatroomName, 136 | state: {chatHistory}, 137 | }), 138 | ) 139 | } 140 | /> 141 | ) 142 | } 143 | /> 144 | { 149 | const toHome = () => props.history.push('/'); 150 | return this.renderUserSelectionOrRedirect(() => ( 151 | this.register(name, toHome)} 155 | /> 156 | )); 157 | } 158 | } 159 | /> 160 | { 161 | this.state.chatrooms.map(chatroom => ( 162 | this.renderChatroomOrRedirect(chatroom, 168 | props) 169 | } 170 | /> 171 | )) 172 | } 173 | 174 | ) 175 | } 176 | 177 | 178 | 179 | ); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /lesson-6/demo/client/scripts/Chatroom.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components' 3 | import RaisedButton from 'material-ui/RaisedButton'; 4 | import TextField from 'material-ui/TextField'; 5 | import FloatingActionButton from 'material-ui/FloatingActionButton'; 6 | import FontIcon from 'material-ui/FontIcon'; 7 | import Avatar from 'material-ui/Avatar'; 8 | import Divider from 'material-ui/Divider'; 9 | import { List, ListItem } from 'material-ui/List'; 10 | 11 | import Overlay from './Overlay'; 12 | 13 | const ChatWindow = styled.div` 14 | position: relative; 15 | display: inline-flex; 16 | flex-direction: column; 17 | justify-content: flex-end; 18 | height: 100%; 19 | width: 420px; 20 | box-sizing: border-box; 21 | ` 22 | const ChatPanel = styled.div` 23 | position: relative; 24 | display: inline-flex; 25 | flex-direction: column; 26 | justify-content: flex-end; 27 | height: 100%; 28 | width: 100%; 29 | box-sizing: border-box; 30 | z-index: 1; 31 | ` 32 | 33 | const Header = styled.div` 34 | display: flex; 35 | align-items: center; 36 | justify-content: space-between; 37 | margin: 0 20px ; 38 | z-index: 1; 39 | color: #fafafa !important; 40 | border-bottom: 1px solid; 41 | ` 42 | 43 | const Title = styled.p` 44 | text-align: center; 45 | font-size: 24px; 46 | ` 47 | 48 | const NoDots = styled.div` 49 | hr { 50 | visibility: hidden; 51 | } 52 | ` 53 | 54 | const OutputText = styled.div` 55 | white-space: normal !important; 56 | word-break: break-all !important; 57 | overflow: initial !important; 58 | width: 100%; 59 | height: auto !important; 60 | color: #fafafa !important; 61 | ` 62 | 63 | const InputPanel = styled.div` 64 | display: flex; 65 | align-items: center; 66 | padding: 20px; 67 | align-self: center; 68 | border-top: 1px solid #fafafa; 69 | ` 70 | 71 | const ChatroomImage = styled.img` 72 | position: absolute; 73 | top: 0; 74 | width: 100%; 75 | ` 76 | 77 | const Scrollable = styled.div` 78 | height: 100%; 79 | overflow: auto; 80 | ` 81 | 82 | export default class Chatroom extends React.Component { 83 | constructor(props, context) { 84 | super(props, context) 85 | 86 | const { chatHistory } = props 87 | 88 | this.state = { 89 | chatHistory, 90 | input: '' 91 | } 92 | 93 | this.onInput = this.onInput.bind(this) 94 | this.onSendMessage = this.onSendMessage.bind(this) 95 | this.onMessageReceived = this.onMessageReceived.bind(this) 96 | this.updateChatHistory = this.updateChatHistory.bind(this) 97 | this.scrollChatToBottom = this.scrollChatToBottom.bind(this) 98 | } 99 | 100 | componentDidMount() { 101 | this.props.registerHandler(this.onMessageReceived) 102 | this.scrollChatToBottom() 103 | } 104 | 105 | componentDidUpdate() { 106 | this.scrollChatToBottom() 107 | } 108 | 109 | componentWillUnmount() { 110 | this.props.unregisterHandler() 111 | } 112 | 113 | onInput(e) { 114 | this.setState({ 115 | input: e.target.value 116 | }) 117 | } 118 | 119 | onSendMessage() { 120 | if (!this.state.input) 121 | return 122 | 123 | this.props.onSendMessage(this.state.input, (err) => { 124 | if (err) 125 | return console.error(err) 126 | 127 | return this.setState({ input: '' }) 128 | }) 129 | } 130 | 131 | onMessageReceived(entry) { 132 | console.log('onMessageReceived:', entry) 133 | this.updateChatHistory(entry) 134 | } 135 | 136 | updateChatHistory(entry) { 137 | this.setState({ chatHistory: this.state.chatHistory.concat(entry) }) 138 | } 139 | 140 | scrollChatToBottom() { 141 | this.panel.scrollTo(0, this.panel.scrollHeight) 142 | } 143 | 144 | render() { 145 | return ( 146 |
147 | 148 |
149 | 150 | { this.props.chatroom.name } 151 | 152 | 159 | {'close'} 160 | 161 | } 162 | onClick={this.props.onLeave} 163 | /> 164 |
165 | 169 | 170 | { this.panel = panel; }}> 171 | 172 | { 173 | this.state.chatHistory.map( 174 | ({ user, message, event }, i) => [ 175 | 176 | } 180 | primaryText={`${user.name} ${event || ''}`} 181 | secondaryText={ 182 | message && 183 | 184 | { message } 185 | 186 | } 187 | /> 188 | , 189 | 190 | ] 191 | ) 192 | } 193 | 194 | 195 | 196 | (e.key === 'Enter' ? this.onSendMessage() : null)} 208 | /> 209 | 213 | 217 | {'chat_bubble_outline'} 218 | 219 | 220 | 221 | 222 | 226 |
227 |
228 | ) 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /lesson-3/README.md: -------------------------------------------------------------------------------- 1 | # Lesson 3. Express - фреймворк для веб приложений 2 | 3 | - Начало работы с Express. 4 | - Сервер. Маршрутизация, статические файлы 5 | - Обработка форм, POST, GET запросы 6 | - JSON, АJAX 7 | - Конвеер обработки и middleware 8 | 9 | 10 | ## Начало работы с Express 11 | 12 | Express представляет собой популярный веб-фреймворк, написанный на JavaScript и работающий внутри среды исполнения node.js. 13 | 14 | Он позволяет вам очень просто создать такие возможности в вашем проекте как: 15 | 16 | - маршрутизация (роутинг) 17 | - промежуточные обработчики (middleware) 18 | - шаблонизация 19 | - обработка ошибок 20 | - дебаг (отладка) 21 | - интеграция с базами данных 22 | 23 | ### Middleware (промежуточный обработчик) 24 | 25 | Это функция которая имеет доступ к запросу (request) и ответу (response). 26 | Функция может делать любые действия и передавать их результат в response или в следующий middleware. 27 | 28 | В экспрессе в middleware есть так же 3й аргумент `next`. Он позволяет перейти сразу к следующемо обработчику события. 29 | 30 | Пример: 31 | ``` 32 | var myLogger = function (req, res, next) { 33 | console.log('LOGGED'); 34 | next(); 35 | }; 36 | ``` 37 | 38 | **Для чего можно использовать Middleware:** 39 | - логирование 40 | - отлов ошибок 41 | - преобразование данных с request 42 | - проверка залогинен ли пользователь (аутентификация) 43 | 44 | 45 | Вот так выглядит использование middleware в коде 46 | ```js 47 | var express = require('express'); 48 | var app = express(); 49 | 50 | // создание middleware 51 | var requestTime = function (req, res, next) { 52 | // Пример: добавляем время к запросу 53 | req.requestTime = Date.now(); 54 | next(); 55 | }; 56 | 57 | // добавление middleware ко всем роутам 58 | app.use(requestTime); 59 | 60 | app.get('/', function (req, res) { 61 | var responseText = 'Hello World!'; 62 | responseText += 'Requested at: ' + req.requestTime + ''; 63 | res.send(responseText); 64 | }); 65 | 66 | app.get('/subscribers/:id', 67 | // добавление middleware к определенному роуту 68 | function checkIfPaidSubscriber(req, res, next) { 69 | if(!req.user.hasPaid) { 70 | 71 | // continue handling this request 72 | next('route'); 73 | } 74 | }, 75 | function getPaidContent(req, res) { 76 | PaidContent.find(function(err, doc) { 77 | if(err) return next(err); 78 | res.json(doc); 79 | }); 80 | }); 81 | 82 | app.listen(3000); 83 | ``` 84 | 85 | ### Шаблонизация 86 | 87 | С помощью Express можно сделать статический сайт, который будет перезагружатся после открытия каждой страницы. Либо же после каждого измненения (если на сайте будет что-то меняться). Как например этот сайт на php https://metanit.com/ 88 | 89 | Для того чтобы отображать в Express файлы шаблонов, необходимо задать следующие параметры приложения: 90 | 91 | **views** - каталог, в котором находятся файлы шаблонов. Например: app.set('views', './views') 92 | 93 | **view engine** - используемый шаблонизатор. Например: app.set('view engine', 'pug') 94 | 95 | Cначала нам нужно установить шаблонизатор. Например `pug` https://pugjs.org/api/getting-started.html 96 | 97 | Следующим шагом создаем шаблон `index.pug` 98 | 99 | ``` 100 | html 101 | head 102 | title= title 103 | body 104 | h1= message 105 | ``` 106 | `title` и `message` это переменные вместо которых можно что-то подставить 107 | 108 | Затем создаем роут для вывода файла index.pug. Если свойство view engine не задано, необходимо указать расширение файла view. В противном случае, можно не указывать расширение. 109 | 110 | ``` 111 | app.get('/', function (req, res) { 112 | res.render('index', { title: 'Hey', message: 'Hello there!'}); 113 | }); 114 | ``` 115 | 116 | При выполнении запроса к домашней странице файл index.pug будет отображаться как HTML. 117 | 118 | Статьи: 119 | - http://expressjs.com/ru/guide/using-template-engines.html 120 | - создание своего шаблонизатора http://expressjs.com/ru/advanced/developing-template-engines.html 121 | 122 | ### Обработка ошибок 123 | 124 | Если в JS возникает ошибка что никак не обрабатывается то JS перестает выполнятся дальше. По этому особенно важно отлавливать ошибки в вашем бекенд приложении. Иначе он просто упадет. 125 | 126 | Такие функции реализуются с помощью `middleware`, но с указанием для функции обработки ошибок не трех, а четырех аргументов: (err, req, res, next). 127 | 128 | Пример: 129 | 130 | ``` 131 | app.use(function(err, req, res, next) { 132 | console.error(err.stack); 133 | res.status(500).send('Something broke!'); 134 | }); 135 | ``` 136 | 137 | Обработчик для обработки ошибок должен быть определен последним, после указания всех app.use() и вызовов роутов; 138 | 139 | Пример: 140 | ``` 141 | var bodyParser = require('body-parser'); 142 | var methodOverride = require('method-override'); 143 | 144 | app.use(bodyParser()); 145 | app.use(methodOverride()); 146 | app.use(logErrors); 147 | app.use(clientErrorHandler); 148 | app.use(errorHandler); 149 | ``` 150 | 151 | Так же в Express предусмотрен встроенный обработчик ошибок, который обрабатывает любые возможные ошибки, встречающиеся в приложении. Этот стандартный обработчик ошибок добавляется в конец всех функций промежуточной обработки(middleware). 152 | 153 | 154 | 155 | ### Отладка (debug) 156 | 157 | В Express используется внутренний модуль debug для регистрации информации о сопоставлениях маршрутов, используемых функциях промежуточной обработки, режиме приложения и выполнении цикла “запрос-ответ”. 158 | 159 | При запуске команды вам в консоли выведутся все операции что были сделаны за определенные время. 160 | 161 | Например 162 | 163 | ``` 164 | const debug = require('debug')('http') 165 | const http = require('http') 166 | const name = 'My App'; 167 | 168 | debug('booting %o', name); 169 | 170 | http.createServer(function(req, res){ 171 | debug(req.method + ' ' + req.url); 172 | res.end('hello\n'); 173 | }).listen(3000, function(){ 174 | debug('listening'); 175 | }); 176 | 177 | ``` 178 | 179 | В консоли вы увидите 180 | 181 | 182 | 183 | Список всех операций и сколько времени заняла каждая их них. 184 | 185 | Более детально: 186 | - https://expressjs.com/ru/guide/debugging.html 187 | - https://www.npmjs.com/package/debug 188 | 189 | ### Задание: 190 | 191 | 1. Перенести все запросы что сделали до этого на Express 192 | - GET `/products/:id` - получение товара 193 | - получаем `id` параметр с запроса 194 | - находим товар в `` 195 | - отправляем json с товаром 196 | - если товара нет отправляем json с {'status': 'no products', 'products': []} 197 | 198 | - GET `/products/?ids=', ,'` - получение нескольких товаров 199 | - получаем `id`шки с запроса 200 | - находим товары в `` 201 | - отправляем json с товарами 202 | - если товара нет отправляем json с {'status': 'no products', 'products': []} 203 | 204 | - POST `/users` - создание юзера 205 | - получаем json с юзером 206 | - добавляем к нему уникальный `id` 207 | - сохраняем юзера в `` 208 | - отправляем json с юзером и полем `success` 209 | ``` 210 | { 211 | "status": "success", 212 | "user": 213 | } 214 | ``` 215 | - GET `/users/:id` - получение юзера 216 | - получаем `id` параметр с запроса 217 | - находим юзера в `` 218 | - отправляем json с юзером 219 | - если юзером нет отправляем json с {'status': 'not found'} 220 | 221 | 222 | #### Новый функцинал 223 | 224 | - POST `/orders/` - создание заказа 225 | - в `body` шлем параметры заказа 226 | ``` 227 | { 228 | "user": , 229 | "products": [, , ] 230 | "deliveryType": "delivery" 231 | "deliveryAdress": "" 232 | } 233 | ``` 234 | - находим товары в `` 235 | - создаем в папке с юзером папку `orders` 236 | - создаем в `orders` новый json с тем что пришло нам из запроса 237 | - отправляем json с готовым заказом 238 | ``` 239 | { 240 | "status": "success", 241 | "order": { 242 | "id": , 243 | "user": , 244 | "products": [, , ] 245 | "deliveryType": "delivery" 246 | "deliveryAdress": "" 247 | } 248 | } 249 | ``` 250 | - если товара нет отправляем json с {'status': 'failed', 'order': null} 251 | 252 | #### Доп задание 253 | 254 | - Реализовать `multipart-data` запрос c отправлением картинки и данных юзера 255 | - POST `/images` - создание картинки 256 | - в теле запроса должна быть картинка и `id` товара которому нужно добавить эту картинку 257 | - похожая реализация есть в `demo/routes/image/save-image-multipart` 258 | - для копирования картинки из папки в папку использовать `stream` (поток) 259 | 260 | **Как выглядит запрос из postman** 261 | 262 | 263 | 264 | 265 | - в ответе должен приходить адрес новой картинки 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /lesson-4/README.md: -------------------------------------------------------------------------------- 1 | # Lesson 4. Node js потоки 2 | 3 | - Синхронность, асинхронность процессов 4 | - синхронные асинхронные методы 5 | - event loop 6 | - promise object 7 | - async, await 8 | - Потоки в node js 9 | 10 | ## Синхронность, асинхронность процессов 11 | 12 | В традиционной практике программирования большинство операций ввода-вывода происходит синхронно. 13 | 14 | Что происходит в фоновом режиме? Основной поток будет заблокирован до тех пор, пока файл не будет прочитан, а это означает, что за это время ничего другого не может быть сделано. Чтобы решить эту проблему и лучше использовать ваш CPU, вам придется управлять потоками вручную. 15 | 16 | Если у вас больше блокирующих операций, очередь событий становится ещё хуже: 17 | 18 | 19 | 20 | Красные полосы отображают промежутки времени, в которые процесс ожидает ответа от внешнего ресурса и блокируется, чёрные полосы показывают, когда ваш код работает, зелёные полосы отображают остальную часть приложения 21 | 22 | Для решения этой проблемы Node.js предлагает модель асинхронного программирования. 23 | 24 | [Асинхронное програмирование в node js](https://medium.com/devschacht/node-hero-chapter-3-cae7333c7f3d) 25 | 26 | ## Event loop 27 | 28 | Цикл событий (Event Loop) — это то, что позволяет Node.js выполнять неблокирующие операции ввода/вывода (несмотря на то, что JavaScript является однопоточным) путем выгрузки операций в ядро системы, когда это возможно. 29 | 30 | [Лучшее видео об event loop](https://www.youtube.com/watch?v=8cV4ZvHXQL4) 31 | 32 | [Ссылка на презентацию по event loop](https://drive.google.com/open?id=1OBMSG1HyNa13DtI_J_csFMvk0O6S9pQK) 33 | 34 | ### Promise 35 | 36 | 37 | В JavaScript «промисы» представляет собой конечный результат выполнения асинхронной операции. Их можно рассматривать в качестве своеобразного «заполнителя». Такой «заполнитель», по существу, является объектом, к которому мы можем привязать функции обратного вызова (колбэки). 38 | 39 | Всего существует 3 возможных состояния для промисов: 40 | 41 | - Pending (ожидание) означает, что асинхронная операция выполняется; 42 | - Fulfilled (успешное выполнение) означает, что операция была выполнена успешно, а промисам было присвоено определенное значение; 43 | - Rejected (выполнено с ошибкой) означает, что во время выполнения операции произошла ошибка. 44 | 45 | 46 | В том случае если состояние промиса не находится в ожидании обработки (pending), то промис считается выполненным, при чем выполненным окончательно: его состояние не может меняться. 47 | 48 | 49 | [Статья по промисам 1](https://habr.com/company/zerotech/blog/317256/) 50 | [Статья по промисам 2](https://blog.liveedu.tv/javascript-promises/) 51 | 52 | #### Видео по промисам 53 | 54 | - https://www.youtube.com/watch?v=SjNmkeUpQAU 55 | - https://www.youtube.com/watch?v=s6SH72uAn3Q 56 | 57 | ## Потоки в node js (Streams) 58 | 59 | Поток — это концепция, которая была сначала реализована в UNIX системах для передачи данных из одной программы в другую в операциях ввода/вывода. Это позволяет каждой программе быть очень специализированной в том, что она делает — быть независимым модулем. Сочетание таких простых программ помогает в создании более сложных систем путем «объединения» их в цепочку вызовов. 60 | 61 | Распространенная задача — парсинг файла большого объема. Например, в текстовом файле с данными логов нужно найти строку, содержащую определенный текст. Вместо того, чтобы файл полностью загрузить в память, и потом начать разбирать в нем строки в поисках нужной, мы можем его считывать небольшими порциями. Тем самым не занимаем память сверх необходимого, а лишь столько памяти, сколько нужно для буферизации считанных данных. Как только найдем требуемую запись, сразу прекратим дальнейшую работу. Или можем передать найденную запись в другой поток по цепочке, например, для преобразование в другой формат, или сохранения в другой файл. 62 | 63 | Самое большое преимущество потоков по сравнению с одновременной загрузкой всех данных состоит в том, что входные данные могут быть бесконечными и без ограничений. 64 | 65 | Как только поток открывается, данные передаются блоками (chunks) из своего источника в процесс, потребляющий их. Поступая из файла, каждый символ или байт считывается по одному. 66 | 67 | Модуль stream предоставляет базовый API по работе с потоками в Node.JS. Документации Node.JS вполне достаточно, чтобы разобраться в данном вопросе, но мы попытаемся составить что-то вроде шпаргалки с пояснениями некоторых моментов. 68 | 69 | ### Виды потоков 70 | 71 | #### Есть четыре вида потоков: 72 | 73 | - **Readable** — поток, который предоставляет данные на чтение; 74 | - **Writable** — поток, в который данные можно записывать; 75 | - **Duplex** — поток, из которого можно как читать данные (Readable), так и записывать в него (Writable), при этом процесс чтения и записи просиходит независимо друго от друга; 76 | - **Transform** — разновидность Duplex потоков, которые могут изменять данные при их записи и чтении в/из потока (чаще используется как промежуточное звено в цепочке передачи данных). 77 | 78 | 79 | Видео для лучшего пониманию потоков 80 | - https://www.youtube.com/watch?v=TobCwECU5Bs 81 | - https://www.youtube.com/watch?v=GpGTYp_G9VE 82 | 83 | ## Readable stream 84 | 85 | [Видео](https://www.youtube.com/watch?v=E3tTzx0Qoj0) 86 | 87 | ### `fs.readFile` vs `streams` 88 | 89 | По умолчанию стандарт чтения текстовых файлов есть использование `fs.readFile(filename, “utf8")` 90 | 91 | Преимущество в node.js для `createReadStream` заключается в том, чтобы читать файл в кусках по 16 Кбайт за раз. Как только мы прочитаем первый фрагмент, мы получим заголовок этой строки, а затем немедленно уничтожим поток, чтобы он больше не читал фрагменты. Это позволяет нам быстро работать независимо от размера файла. 92 | 93 | И вот сравнение для чтения в CSV разных размеров, размером от 164 КБ до 160 МБ (ось х - это строки CSV / размер файла, ось у - это время, затраченное на соответствующую функцию read.js для чтения файлов): 94 | 95 | 96 | 97 | Как вы можете видеть, `stream` метод остается в значительной степени плоским и быстрым, тогда как метод `readFile` начинает заметно возрастать, когда мы приближаемся к размеру файла размером ~ 16 МБ. 98 | 99 | Если вы планируете иметь дело с текстовыми файлами большего размера, чем около 10 МБ, лучше всего не использовать `readFile` и вместо этого использовать потоки. 100 | 101 | Есть еще одна вещь, чтобы упомянуть, использование потока кажется немного более быстрым при работе с файлом 100000+ строк по сравнению с меньшими размерами файлов. 102 | 103 | [Статья](https://medium.com/tensult/stream-and-buffer-concepts-in-node-js-87d565e151a0) 104 | 105 | ### Writable stream 106 | 107 | В поток на запись можно послать данные используя метод `stream.write`, но прочитать их уже не получится: 108 | 109 | `src.pipe(writableStream)` 110 | 111 | 112 | ``` 113 | var fs = require("fs"); 114 | var data = 'Simply Easy Learning'; 115 | 116 | // Create a writable stream 117 | var writerStream = fs.createWriteStream('output.txt'); 118 | 119 | // Write the data to stream with encoding to be utf8 120 | writerStream.write(data,'UTF8'); 121 | 122 | // Mark the end of file 123 | writerStream.end(); 124 | 125 | // Handle stream events --> finish, and error 126 | writerStream.on('finish', function() { 127 | console.log("Write completed."); 128 | }); 129 | 130 | writerStream.on('error', function(err){ 131 | console.log(err.stack); 132 | }); 133 | 134 | console.log("Program Ended"); 135 | 136 | ``` 137 | 138 | [Видео по Writable stream](https://www.youtube.com/watch?v=DvlCT0N7yQI) 139 | 140 | ### Преобразование данных 141 | 142 | Потоки хороши не только для передачи данных между различными источниками и адресатами. 143 | 144 | Когда после открытия потока данные становятся доступны, разработчики могут преобразовывать данные, поступающие из потока, до того, как они достигнут своего адресата, например, преобразовывая все символы нижнего регистра в файле в символы верхнего регистра. 145 | 146 | Это одна из величайших сил потоков. Как только поток открывается и вы можете прочитать данные по частям, вы можете вставить различные программы в промежутке. Этот процесс показан на рисунке ниже. 147 | 148 | ### Pipe метод 149 | 150 | Любой поток может использовать.pipe() для соединения входов с выходами. 151 | 152 | .pipe() это просто функция, которая берет поток на чтение src и соединяет его вывод с вводом потока на запись. 153 | 154 | Чтобы передать данные из одного потока в другой, самый простой способ вызвать над потоками метод pipe: 155 | 156 | ``` 157 | Readable.pipe(Writable);//например, по "схеме" DataBase -> File 158 | Readable.pipe(Transform).pipe(Writable);//DataBase -> преобразовать в JSON формат -> сохранить JSON в File 159 | Duplex.pipe(Transform).pipe(Duplex);//прочитать из DataBase -> обработать -> записать обратно в DataBase результат 160 | ``` 161 | 162 | Последняя цепочка вызовов показывает, что реализовывать свои классы потоков лучше таким образом, чтобы каждый их них решал свою задачу. 163 | 164 | Как видно — метод pipe возвращает экземпляр потока, который был передан в него, что и позволяет потоки объединять между собой. 165 | 166 | Метод pipe, реализован таким образом, что он решает задачу контроля «скорости» передачи данных из одного потока в другой (превышение объема внутреннего буфера потока). Например, Writable поток работает на запись медленнее, чем их передает источник данных Readable. В этом случае передача данных «приостанавливается» до тех пор, пока Writable «не сообщит» (внутренний буфер очистится), что он готов принимать следующую порцию данных. --------------------------------------------------------------------------------