From 695b615dae903bba2d49547789abe5086535a2b3 Mon Sep 17 00:00:00 2001 From: CarlosDaniel396 Date: Mon, 17 Jan 2022 22:44:14 -0400 Subject: [PATCH 1/6] Fazer readme --- .../template-testes-backend-feito/.rest | 21 ++++++++++++++++ .../.vscode/launch.json | 20 +++++++++++++++ semana22/amaro/readme.md | 25 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 semana21/aula64/template-testes-backend-feito/.rest create mode 100644 semana21/aula64/template-testes-backend-feito/.vscode/launch.json create mode 100644 semana22/amaro/readme.md diff --git a/semana21/aula64/template-testes-backend-feito/.rest b/semana21/aula64/template-testes-backend-feito/.rest new file mode 100644 index 0000000..145d378 --- /dev/null +++ b/semana21/aula64/template-testes-backend-feito/.rest @@ -0,0 +1,21 @@ +### CADASTRO + +POST http://localhost:3003/users/signup +Content-Type: application/json + +{ + "name": "Alice", + "email": "alice@lbn.com", + "password": "123456", + "role":"ADMIN" +} + +### LOGIN + +POST http://localhost:3003/users/login +Content-Type: application/json + +{ + "email": "alice@lbn.com", + "password": "123456" +} \ No newline at end of file diff --git a/semana21/aula64/template-testes-backend-feito/.vscode/launch.json b/semana21/aula64/template-testes-backend-feito/.vscode/launch.json new file mode 100644 index 0000000..2068be4 --- /dev/null +++ b/semana21/aula64/template-testes-backend-feito/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/build/src/index.js", + "outFiles": [ + "${workspaceFolder}/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/semana22/amaro/readme.md b/semana22/amaro/readme.md new file mode 100644 index 0000000..64c39e4 --- /dev/null +++ b/semana22/amaro/readme.md @@ -0,0 +1,25 @@ +Desafio back-end AMARO +Sobre o desafio +Criação de API para cadastro e consulta de produtos +Você precisa criar uma API com os seguintes requisitos: + +End-point para inserção de dados +O cliente poderá enviá-los em arquivos json ou xml e a API deverá inserir no banco de dados. +Escolha o banco de dados que achar melhor. +End-point para consulta destes produtos +Pode ser consultado por: id, nome ou tags. Caso a consulta seja por uma tag ou nome, deverá listar todos os produtos com aquela respectiva busca, poderá ser feito em um ou mais end-points. +Requisitos Obrigatórios +Ter uma cobertura de teste relativamente boa, a maior que você conseguir. +Usar PHP +Pode usar qualquer framework PHP para o desenvolvimento ou não usar nenhum, fica a sua escolha. +Criar um cache para consulta. +PLUS - Não necessário +Colocar uma autenticação JWT. +Usar PHP 7.1 +Orientações +Procure fazer uma API sucinta. +Os arquivos (json, xml) junto com o formato que o cliente irá enviar estão no repositório. +Pensa em escalabilidade, pode ser uma quantidade muito grande de dados. +Coloque isso em um repositório GIT. +Colocar as orientações de setup no README do seu repositório. +Boa sorte From 8f4c2da542bd4b379877580b721afa710123d431 Mon Sep 17 00:00:00 2001 From: CarlosDaniel396 Date: Tue, 18 Jan 2022 11:37:59 -0400 Subject: [PATCH 2/6] Atualizar readme --- semana22/amaro/readme.md | 59 +++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/semana22/amaro/readme.md b/semana22/amaro/readme.md index 64c39e4..1bb882c 100644 --- a/semana22/amaro/readme.md +++ b/semana22/amaro/readme.md @@ -1,25 +1,34 @@ -Desafio back-end AMARO -Sobre o desafio -Criação de API para cadastro e consulta de produtos -Você precisa criar uma API com os seguintes requisitos: - -End-point para inserção de dados -O cliente poderá enviá-los em arquivos json ou xml e a API deverá inserir no banco de dados. -Escolha o banco de dados que achar melhor. -End-point para consulta destes produtos -Pode ser consultado por: id, nome ou tags. Caso a consulta seja por uma tag ou nome, deverá listar todos os produtos com aquela respectiva busca, poderá ser feito em um ou mais end-points. -Requisitos Obrigatórios -Ter uma cobertura de teste relativamente boa, a maior que você conseguir. -Usar PHP -Pode usar qualquer framework PHP para o desenvolvimento ou não usar nenhum, fica a sua escolha. -Criar um cache para consulta. -PLUS - Não necessário -Colocar uma autenticação JWT. -Usar PHP 7.1 -Orientações -Procure fazer uma API sucinta. -Os arquivos (json, xml) junto com o formato que o cliente irá enviar estão no repositório. -Pensa em escalabilidade, pode ser uma quantidade muito grande de dados. -Coloque isso em um repositório GIT. -Colocar as orientações de setup no README do seu repositório. -Boa sorte +### Desafio back-end AMARO + +### Sobre o desafio + +- Criação de API para cadastro e consulta de produtos +- Você precisa criar uma API com os seguintes requisitos: + +#### End-point para inserção de dados + +- O cliente poderá enviá-los em arquivos json ou xml e a API deverá inserir no banco de dados. +- Escolha o banco de dados que achar melhor. + +### End-point para consulta destes produtos + +-Pode ser consultado por: id, nome ou tags. Caso a consulta seja por uma tag ou nome, deverá listar todos os produtos com aquela respectiva busca, poderá ser feito em um ou mais end-points. + +### Requisitos Obrigatórios + +- Ter uma cobertura de teste relativamente boa, a maior que você conseguir. +- Usar NodeJS +- Criar um cache para consulta. + +### PLUS - Não necessário + +- Colocar uma autenticação JWT. + +### Orientações + +- Procure fazer uma API sucinta. +- Os arquivos (json, xml) junto com o formato que o cliente irá enviar estão no repositório. +- Pense em escalabilidade, pode ser uma quantidade muito grande de dados. +- Coloque isso em um repositório GIT. +- Colocar as orientações de setup no README do seu repositório. +- Boa sorte! From 54938e1240eed479fdb054ba5135d3cf32aaf27f Mon Sep 17 00:00:00 2001 From: CarlosDaniel396 Date: Tue, 18 Jan 2022 15:09:23 -0400 Subject: [PATCH 3/6] Fazer migrations --- semana22/amaro/.gitignore | 4 ++ semana22/amaro/package.json | 34 +++++++++ .../src/business/UserBusiness/UserBusiness.ts | 0 .../UserController/UserController.ts | 0 semana22/amaro/src/controller/app.ts | 11 +++ semana22/amaro/src/data/BaseDatabase.ts | 15 ++++ .../src/data/UserDataBase/UserDataBase.ts | 0 semana22/amaro/src/entities/Product.ts | 6 ++ semana22/amaro/src/entities/User.ts | 6 ++ semana22/amaro/src/index.ts | 1 + semana22/amaro/src/migrations.ts | 24 +++++++ semana22/amaro/src/services/Authenticator.ts | 20 ++++++ semana22/amaro/src/services/HashManager.ts | 13 ++++ semana22/amaro/src/services/IdGenerator.ts | 5 ++ semana22/amaro/tsconfig.json | 69 +++++++++++++++++++ 15 files changed, 208 insertions(+) create mode 100644 semana22/amaro/.gitignore create mode 100644 semana22/amaro/package.json create mode 100644 semana22/amaro/src/business/UserBusiness/UserBusiness.ts create mode 100644 semana22/amaro/src/controller/UserController/UserController.ts create mode 100644 semana22/amaro/src/controller/app.ts create mode 100644 semana22/amaro/src/data/BaseDatabase.ts create mode 100644 semana22/amaro/src/data/UserDataBase/UserDataBase.ts create mode 100644 semana22/amaro/src/entities/Product.ts create mode 100644 semana22/amaro/src/entities/User.ts create mode 100644 semana22/amaro/src/index.ts create mode 100644 semana22/amaro/src/migrations.ts create mode 100644 semana22/amaro/src/services/Authenticator.ts create mode 100644 semana22/amaro/src/services/HashManager.ts create mode 100644 semana22/amaro/src/services/IdGenerator.ts create mode 100644 semana22/amaro/tsconfig.json diff --git a/semana22/amaro/.gitignore b/semana22/amaro/.gitignore new file mode 100644 index 0000000..8ece3ba --- /dev/null +++ b/semana22/amaro/.gitignore @@ -0,0 +1,4 @@ +node_modules +package-lock.json +build +.env \ No newline at end of file diff --git a/semana22/amaro/package.json b/semana22/amaro/package.json new file mode 100644 index 0000000..a5d06d8 --- /dev/null +++ b/semana22/amaro/package.json @@ -0,0 +1,34 @@ +{ + "name": "amaro", + "version": "1.0.0", + "description": "### Sobre o desafio", + "main": "index.js", + "scripts": { + "dev": "ts-node-dev ./src/index.ts", + "start": "tsc && node ./build/index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/bcryptjs": "^2.4.2", + "@types/knex": "^0.16.1", + "@types/uuid": "^8.3.4", + "typescript": "^4.5.4" + }, + "dependencies": { + "@types/cors": "^2.8.12", + "@types/express": "^4.17.13", + "@types/jsonwebtoken": "^8.5.8", + "bcryptjs": "^2.4.3", + "cors": "^2.8.5", + "dotenv": "^14.2.0", + "express": "^4.17.2", + "jsonwebtoken": "^8.5.1", + "knex": "^1.0.1", + "mysql": "^2.18.1", + "ts-node-dev": "^1.1.8", + "uuid": "^8.3.2" + } +} diff --git a/semana22/amaro/src/business/UserBusiness/UserBusiness.ts b/semana22/amaro/src/business/UserBusiness/UserBusiness.ts new file mode 100644 index 0000000..e69de29 diff --git a/semana22/amaro/src/controller/UserController/UserController.ts b/semana22/amaro/src/controller/UserController/UserController.ts new file mode 100644 index 0000000..e69de29 diff --git a/semana22/amaro/src/controller/app.ts b/semana22/amaro/src/controller/app.ts new file mode 100644 index 0000000..7a745f2 --- /dev/null +++ b/semana22/amaro/src/controller/app.ts @@ -0,0 +1,11 @@ +import express from "express"; +import cors from "cors"; + +export const app = express(); + +app.use(express.json()); +app.use(cors()); + +app.listen(3003, () => { + console.log("Server runin on port 3003"); +}); diff --git a/semana22/amaro/src/data/BaseDatabase.ts b/semana22/amaro/src/data/BaseDatabase.ts new file mode 100644 index 0000000..9a5ac4f --- /dev/null +++ b/semana22/amaro/src/data/BaseDatabase.ts @@ -0,0 +1,15 @@ +import knex from "knex"; + +export class BaseDatabase { + protected connection = knex({ + client: "mysql", + connection: { + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_SCHEMA, + port: 3306, + multipleStatements: true, + }, + }); +} diff --git a/semana22/amaro/src/data/UserDataBase/UserDataBase.ts b/semana22/amaro/src/data/UserDataBase/UserDataBase.ts new file mode 100644 index 0000000..e69de29 diff --git a/semana22/amaro/src/entities/Product.ts b/semana22/amaro/src/entities/Product.ts new file mode 100644 index 0000000..cfb067e --- /dev/null +++ b/semana22/amaro/src/entities/Product.ts @@ -0,0 +1,6 @@ +export interface Product { + id: string; + name: string; + price: number; + image_url: string; +} diff --git a/semana22/amaro/src/entities/User.ts b/semana22/amaro/src/entities/User.ts new file mode 100644 index 0000000..2a80a3d --- /dev/null +++ b/semana22/amaro/src/entities/User.ts @@ -0,0 +1,6 @@ +export interface User { + id: string; + name: string; + email: string; + password: string; +} diff --git a/semana22/amaro/src/index.ts b/semana22/amaro/src/index.ts new file mode 100644 index 0000000..d597185 --- /dev/null +++ b/semana22/amaro/src/index.ts @@ -0,0 +1 @@ +import { app } from "./controller/app"; diff --git a/semana22/amaro/src/migrations.ts b/semana22/amaro/src/migrations.ts new file mode 100644 index 0000000..1a96bd9 --- /dev/null +++ b/semana22/amaro/src/migrations.ts @@ -0,0 +1,24 @@ +import { BaseDatabase } from "./data/BaseDatabase"; + +export class BaseDatabaseMigrations extends BaseDatabase { + baseDatabase = this.connection + .raw( + `CREATE TABLE IF NOT EXISTS amaro_users ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL + ); + + CREATE TABLE IF NOT EXISTS amaro_products ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(255) NOT NULL, + price FLOAT NOT NULL, + image_url VARCHAR(255) NOT NULL, + user_id VARCHAR(255), + FOREIGN KEY(user_id) REFERENCES amaro_users(id) + );` + ) + .then(console.log) + .catch(console.log); +} diff --git a/semana22/amaro/src/services/Authenticator.ts b/semana22/amaro/src/services/Authenticator.ts new file mode 100644 index 0000000..9cd705a --- /dev/null +++ b/semana22/amaro/src/services/Authenticator.ts @@ -0,0 +1,20 @@ +import * as jwt from "jsonwebtoken"; + +export interface AuthenticationData { + id: string; +} + +export class Authenticator { + generate(input: AuthenticationData): string { + const token = jwt.sign(input, process.env.JWT_KEY as any, { + expiresIn: process.env.ACCESS_TOKEN_EXPIRES_IN, + }); + + return token; + } + + getTokenData(token: string): AuthenticationData { + const data = jwt.verify(token, process.env.JWT_KEY as any); + return data as AuthenticationData; + } +} diff --git a/semana22/amaro/src/services/HashManager.ts b/semana22/amaro/src/services/HashManager.ts new file mode 100644 index 0000000..1c745d2 --- /dev/null +++ b/semana22/amaro/src/services/HashManager.ts @@ -0,0 +1,13 @@ +import * as bcrypt from "bcryptjs"; + +export class HashManager { + async hash(text: string): Promise { + const rounds = Number(process.env.BCRYPT_COST); + const salt = await bcrypt.genSalt(rounds); + return bcrypt.hash(text, salt); + } + + async compare(text: string, hash: string): Promise { + return bcrypt.compare(text, hash); + } +} diff --git a/semana22/amaro/src/services/IdGenerator.ts b/semana22/amaro/src/services/IdGenerator.ts new file mode 100644 index 0000000..3a8b784 --- /dev/null +++ b/semana22/amaro/src/services/IdGenerator.ts @@ -0,0 +1,5 @@ +import { v4 } from "uuid"; + +export class IdGenerator { + generateId = (): string => v4(); +} diff --git a/semana22/amaro/tsconfig.json b/semana22/amaro/tsconfig.json new file mode 100644 index 0000000..3157e37 --- /dev/null +++ b/semana22/amaro/tsconfig.json @@ -0,0 +1,69 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true /* Generates corresponding '.map' file. */, + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./build" /* Redirect output structure to the directory. */, + "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + "removeComments": true /* Do not emit comments to output. */, + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} From 790b5acea64dcf1534b7bb7ccc87f5e7496ba1a6 Mon Sep 17 00:00:00 2001 From: CarlosDaniel396 Date: Tue, 18 Jan 2022 16:32:30 -0400 Subject: [PATCH 4/6] Criar endpoint de cadastro e login --- .../src/business/UserBusiness/UserBusiness.ts | 64 +++++++++++++++++++ .../UserController/UserController.ts | 46 +++++++++++++ .../src/controller/routes/productRouter.ts | 3 + .../amaro/src/controller/routes/userRouter.ts | 9 +++ .../src/data/UserDataBase/UserDataBase.ts | 34 ++++++++++ semana22/amaro/src/entities/User.ts | 22 +++++++ semana22/amaro/src/index.ts | 5 ++ 7 files changed, 183 insertions(+) create mode 100644 semana22/amaro/src/controller/routes/productRouter.ts create mode 100644 semana22/amaro/src/controller/routes/userRouter.ts diff --git a/semana22/amaro/src/business/UserBusiness/UserBusiness.ts b/semana22/amaro/src/business/UserBusiness/UserBusiness.ts index e69de29..d9d4ae0 100644 --- a/semana22/amaro/src/business/UserBusiness/UserBusiness.ts +++ b/semana22/amaro/src/business/UserBusiness/UserBusiness.ts @@ -0,0 +1,64 @@ +import { SignupInputDTO, LoginInputDTO, User } from "../../entities/User"; +import { IdGenerator } from "../../services/IdGenerator"; +import { HashManager } from "../../services/HashManager"; +import { Authenticator } from "../../services/Authenticator"; +import { UserDatabase } from "../../data/UserDataBase/UserDataBase"; + +export class UserBusiness { + async signup(input: SignupInputDTO): Promise { + try { + if (!input.name || !input.email || !input.password) { + throw new Error('"name", "email" and "password" must be provided'); + } + + const idGenerator = new IdGenerator(); + const id: string = idGenerator.generateId(); + + const hashManager = new HashManager(); + const cypherPassword = await hashManager.hash(input.password); + + const user: User = { + id, + name: input.name, + email: input.email, + password: cypherPassword, + }; + + const userDataBase = new UserDatabase(); + await userDataBase.insertUser(user); + + const tokenManager = new Authenticator(); + const token: string = tokenManager.generate({ id }); + + return token; + } catch (error) {} + } + + async login(input: LoginInputDTO): Promise { + try { + if (!input.email || !input.password) { + throw new Error('"email" and "password" must be provided'); + } + + const userDataBase = new UserDatabase(); + const user: User = await userDataBase.getUserByEmail(input.email); + + const hashManager = new HashManager(); + const passwordIsCorrect: boolean = await hashManager.compare( + input.password, + user.password + ); + + if (!user || !passwordIsCorrect) { + throw new Error("Invalid credentials"); + } + + const tokenManager = new Authenticator(); + const token: string = await tokenManager.generate({ id: user.id }); + + return token; + } catch (error: any) { + throw new Error(error.message); + } + } +} diff --git a/semana22/amaro/src/controller/UserController/UserController.ts b/semana22/amaro/src/controller/UserController/UserController.ts index e69de29..f214f3f 100644 --- a/semana22/amaro/src/controller/UserController/UserController.ts +++ b/semana22/amaro/src/controller/UserController/UserController.ts @@ -0,0 +1,46 @@ +import { Request, Response } from "express"; +import { SignupInputDTO, LoginInputDTO } from "../../entities/User"; +import { UserBusiness } from "../../business/UserBusiness/UserBusiness"; + +export class UserController { + async signup(req: Request, res: Response): Promise { + try { + const message = "Success!"; + + const input: SignupInputDTO = { + name: req.body.name, + email: req.body.email, + password: req.body.password, + }; + + const userBusiness = new UserBusiness(); + const token = await userBusiness.signup(input); + + res.status(201).send({ message, token }); + } catch (error: any) { + const message = error.SqlMessage || error.message; + + res.send({ message }); + } + } + + async loginUser(req: Request, res: Response) { + try { + const message = "Success!"; + + const input: LoginInputDTO = { + email: req.body.email, + password: req.body.password, + }; + + const token = await new UserBusiness().login(input); + + res.status(200).send({ message, token }); + } catch (error: any) { + let message = error.sqlMessage || error.message; + res.statusCode = 400; + + res.send({ message }); + } + } +} diff --git a/semana22/amaro/src/controller/routes/productRouter.ts b/semana22/amaro/src/controller/routes/productRouter.ts new file mode 100644 index 0000000..9ea9a2a --- /dev/null +++ b/semana22/amaro/src/controller/routes/productRouter.ts @@ -0,0 +1,3 @@ +import { Router } from "express"; + +export const productRouter = Router(); diff --git a/semana22/amaro/src/controller/routes/userRouter.ts b/semana22/amaro/src/controller/routes/userRouter.ts new file mode 100644 index 0000000..2d51b77 --- /dev/null +++ b/semana22/amaro/src/controller/routes/userRouter.ts @@ -0,0 +1,9 @@ +import { Router } from "express"; +import { UserController } from "../UserController/UserController"; + +export const userRouter = Router(); + +const userController = new UserController(); + +userRouter.post("/signup", userController.signup); +userRouter.post("/login", userController.loginUser); diff --git a/semana22/amaro/src/data/UserDataBase/UserDataBase.ts b/semana22/amaro/src/data/UserDataBase/UserDataBase.ts index e69de29..4bcf444 100644 --- a/semana22/amaro/src/data/UserDataBase/UserDataBase.ts +++ b/semana22/amaro/src/data/UserDataBase/UserDataBase.ts @@ -0,0 +1,34 @@ +import { BaseDatabase } from "../BaseDatabase"; +import { User, toUserModel } from "../../entities/User"; +import dotenv from "dotenv"; + +dotenv.config(); + +export class UserDatabase extends BaseDatabase { + async insertUser(user: User) { + try { + await this.connection("amaro_users").insert({ + id: user.id, + name: user.name, + email: user.email, + password: user.password, + }); + } catch (error: any) { + throw new Error(error.sqlMessage || error.message); + } + } + + async getUserByEmail(email: string): Promise { + try { + const result: any = await this.connection("amaro_users") + .select("*") + .where({ email }); + + const user = toUserModel(result[0]); + + return user; + } catch (error: any) { + throw new Error(error.sqlMessage || error.message); + } + } +} diff --git a/semana22/amaro/src/entities/User.ts b/semana22/amaro/src/entities/User.ts index 2a80a3d..e453358 100644 --- a/semana22/amaro/src/entities/User.ts +++ b/semana22/amaro/src/entities/User.ts @@ -4,3 +4,25 @@ export interface User { email: string; password: string; } + +export interface SignupInputDTO { + name: string; + email: string; + password: string; +} + +export interface LoginInputDTO { + email: string; + password: string; +} + +export function toUserModel(obj: any): User { + return ( + obj && { + id: obj.id, + email: obj.email, + name: obj.name, + password: obj.password, + } + ); +} diff --git a/semana22/amaro/src/index.ts b/semana22/amaro/src/index.ts index d597185..fbbaa21 100644 --- a/semana22/amaro/src/index.ts +++ b/semana22/amaro/src/index.ts @@ -1 +1,6 @@ import { app } from "./controller/app"; +import { userRouter } from "./controller/routes/userRouter"; +import { productRouter } from "./controller/routes/productRouter"; + +app.use("/user", userRouter); +app.post("/product", productRouter); From a2e5cfdbb33c8c48bbe09877ffc3c56e5d54fc9f Mon Sep 17 00:00:00 2001 From: CarlosDaniel396 Date: Tue, 18 Jan 2022 21:18:09 -0400 Subject: [PATCH 5/6] Criar endpointde cadastro de produto --- .../ProductBusiness/ProductBusiness.ts | 42 +++++++++++++++++++ .../ProductController/ProductController.ts | 28 +++++++++++++ .../src/controller/routes/productRouter.ts | 5 +++ .../data/ProductDataBase/ProductDatabase.ts | 21 ++++++++++ semana22/amaro/src/entities/Product.ts | 24 +++++++++++ semana22/amaro/src/index.ts | 2 +- 6 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts create mode 100644 semana22/amaro/src/controller/ProductController/ProductController.ts create mode 100644 semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts diff --git a/semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts b/semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts new file mode 100644 index 0000000..0d6d64e --- /dev/null +++ b/semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts @@ -0,0 +1,42 @@ +import { CreateProductDTO, Product } from "../../entities/Product"; +import { + AuthenticationData, + Authenticator, +} from "../../services/Authenticator"; +import { IdGenerator } from "../../services/IdGenerator"; +import { ProductDatabase } from "../../data/ProductDataBase/ProductDatabase"; + +export class ProductBusiness { + async registerProduct(input: CreateProductDTO): Promise { + try { + const tokenManager = new Authenticator(); + + if (!input.name || !input.price || !input.image_url) { + throw new Error('"Name", "Price" and "image_url" must be provided'); + } + + if (!input.token) { + throw new Error("A jwt must be provided"); + } + + const tokenData: AuthenticationData = tokenManager.getTokenData( + input.token + ); + + const idGenerator = new IdGenerator(); + const id: string = idGenerator.generateId(); + + const product: Product = { + id, + user_id: tokenData.id, + name: input.name, + price: input.price, + image_url: input.image_url, + }; + + await new ProductDatabase().registerProduct(product); + } catch (error: any) { + throw new Error(error.message); + } + } +} diff --git a/semana22/amaro/src/controller/ProductController/ProductController.ts b/semana22/amaro/src/controller/ProductController/ProductController.ts new file mode 100644 index 0000000..c10d28d --- /dev/null +++ b/semana22/amaro/src/controller/ProductController/ProductController.ts @@ -0,0 +1,28 @@ +import { Request, Response } from "express"; +import { CreateProductDTO } from "../../entities/Product"; +import { ProductBusiness } from "../../business/ProductBusiness/ProductBusiness"; + +export class ProductController { + async registerProduct(req: Request, res: Response): Promise { + try { + const message = "Success!"; + + const token: string = req.headers.authorization as string; + + const input: CreateProductDTO = { + name: req.body.name, + price: req.body.price, + image_url: req.body.image_url, + token, + }; + + await new ProductBusiness().registerProduct(input); + + res.status(201).send({ message }); + } catch (error: any) { + const message = error.SqlMessage || error.message; + + res.send({ message }); + } + } +} diff --git a/semana22/amaro/src/controller/routes/productRouter.ts b/semana22/amaro/src/controller/routes/productRouter.ts index 9ea9a2a..28538c3 100644 --- a/semana22/amaro/src/controller/routes/productRouter.ts +++ b/semana22/amaro/src/controller/routes/productRouter.ts @@ -1,3 +1,8 @@ import { Router } from "express"; +import { ProductController } from "../ProductController/ProductController"; export const productRouter = Router(); + +const productController = new ProductController(); + +productRouter.post("/", productController.registerProduct); diff --git a/semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts b/semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts new file mode 100644 index 0000000..3146bfe --- /dev/null +++ b/semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts @@ -0,0 +1,21 @@ +import { BaseDatabase } from "../BaseDatabase"; +import { Product, toProductModel } from "../../entities/Product"; +import dotenv from "dotenv"; + +dotenv.config(); + +export class ProductDatabase extends BaseDatabase { + async registerProduct(product: Product) { + try { + await this.connection("amaro_products").insert({ + id: product.id, + name: product.name, + price: product.price, + image_url: product.image_url, + user_id: product.user_id, + }); + } catch (error: any) { + throw new Error(error.sqlMessage || error.message); + } + } +} diff --git a/semana22/amaro/src/entities/Product.ts b/semana22/amaro/src/entities/Product.ts index cfb067e..f48272e 100644 --- a/semana22/amaro/src/entities/Product.ts +++ b/semana22/amaro/src/entities/Product.ts @@ -3,4 +3,28 @@ export interface Product { name: string; price: number; image_url: string; + user_id: string; +} + +export interface CreateProductDTO { + name: string; + price: number; + image_url: string; + token: string; +} + +export interface GetProductByIdInputDTO { + id: string; +} + +export function toProductModel(obj: any): Product { + return ( + obj && { + id: obj.id, + name: obj.name, + price: obj.price, + image_url: obj.image_url, + authorId: obj.authorId, + } + ); } diff --git a/semana22/amaro/src/index.ts b/semana22/amaro/src/index.ts index fbbaa21..1fb1382 100644 --- a/semana22/amaro/src/index.ts +++ b/semana22/amaro/src/index.ts @@ -3,4 +3,4 @@ import { userRouter } from "./controller/routes/userRouter"; import { productRouter } from "./controller/routes/productRouter"; app.use("/user", userRouter); -app.post("/product", productRouter); +app.use("/product", productRouter); From 7d0cf50a69e0c42ec7af17af61945a9be9b67bf3 Mon Sep 17 00:00:00 2001 From: CarlosDaniel396 Date: Wed, 19 Jan 2022 10:17:55 -0400 Subject: [PATCH 6/6] Criar endpoint de buscar produto por nome --- .../ProductBusiness/ProductBusiness.ts | 24 ++++++++++++++++- .../ProductController/ProductController.ts | 26 ++++++++++++++++++- .../src/controller/routes/productRouter.ts | 1 + .../data/ProductDataBase/ProductDatabase.ts | 12 +++++++++ semana22/amaro/src/entities/Product.ts | 4 +++ 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts b/semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts index 0d6d64e..d715759 100644 --- a/semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts +++ b/semana22/amaro/src/business/ProductBusiness/ProductBusiness.ts @@ -1,4 +1,8 @@ -import { CreateProductDTO, Product } from "../../entities/Product"; +import { + CreateProductDTO, + GetProductByNameDTO, + Product, +} from "../../entities/Product"; import { AuthenticationData, Authenticator, @@ -39,4 +43,22 @@ export class ProductBusiness { throw new Error(error.message); } } + + async getProductByName( + input: GetProductByNameDTO + ): Promise { + try { + const product: Product = await new ProductDatabase().getProductByName( + input.name + ); + + if (!product) { + throw new Error("Product not found"); + } + + return product; + } catch (error: any) { + throw new Error(error.message); + } + } } diff --git a/semana22/amaro/src/controller/ProductController/ProductController.ts b/semana22/amaro/src/controller/ProductController/ProductController.ts index c10d28d..e3e2bf2 100644 --- a/semana22/amaro/src/controller/ProductController/ProductController.ts +++ b/semana22/amaro/src/controller/ProductController/ProductController.ts @@ -1,5 +1,9 @@ import { Request, Response } from "express"; -import { CreateProductDTO } from "../../entities/Product"; +import { + CreateProductDTO, + GetProductByNameDTO, + Product, +} from "../../entities/Product"; import { ProductBusiness } from "../../business/ProductBusiness/ProductBusiness"; export class ProductController { @@ -25,4 +29,24 @@ export class ProductController { res.send({ message }); } } + + async getProductByName(req: Request, res: Response): Promise { + try { + const message = "Success!"; + + const input: GetProductByNameDTO = { + name: req.params.name, + }; + + const product: Product | undefined = + await new ProductBusiness().getProductByName(input); + + res.status(200).send({ message, product }); + } catch (error: any) { + let message = error.sqlMessage || error.message; + res.statusCode = 400; + + res.send({ message }); + } + } } diff --git a/semana22/amaro/src/controller/routes/productRouter.ts b/semana22/amaro/src/controller/routes/productRouter.ts index 28538c3..52f43dd 100644 --- a/semana22/amaro/src/controller/routes/productRouter.ts +++ b/semana22/amaro/src/controller/routes/productRouter.ts @@ -6,3 +6,4 @@ export const productRouter = Router(); const productController = new ProductController(); productRouter.post("/", productController.registerProduct); +productRouter.get("/:name", productController.getProductByName); diff --git a/semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts b/semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts index 3146bfe..92c3543 100644 --- a/semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts +++ b/semana22/amaro/src/data/ProductDataBase/ProductDatabase.ts @@ -18,4 +18,16 @@ export class ProductDatabase extends BaseDatabase { throw new Error(error.sqlMessage || error.message); } } + + async getProductByName(name: string): Promise { + try { + const result = await this.connection("amaro_products") + .select("*") + .where({ name }); + + return toProductModel(result[0]); + } catch (error: any) { + throw new Error(error.sqlMessage || error.message); + } + } } diff --git a/semana22/amaro/src/entities/Product.ts b/semana22/amaro/src/entities/Product.ts index f48272e..b07b1c8 100644 --- a/semana22/amaro/src/entities/Product.ts +++ b/semana22/amaro/src/entities/Product.ts @@ -17,6 +17,10 @@ export interface GetProductByIdInputDTO { id: string; } +export interface GetProductByNameDTO { + name: string; +} + export function toProductModel(obj: any): Product { return ( obj && {