├── 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 «не сообщит» (внутренний буфер очистится), что он готов принимать следующую порцию данных.
--------------------------------------------------------------------------------