From 216edc97fb9c6f2d6edbe6a432dbd5eebcc1ccd6 Mon Sep 17 00:00:00 2001 From: Vsux Date: Tue, 17 May 2022 11:58:54 -0200 Subject: [PATCH 1/6] primeiro teste --- modulo5/case/.gitignore | 4 + modulo5/case/Migrations.ts | 36 ++++++++ modulo5/case/README.md | 41 +++++++++ modulo5/case/jest.config.js | 8 ++ modulo5/case/package.json | 46 ++++++++++ .../case/src/business/GetDetailsBusiness.ts | 24 +++++ modulo5/case/src/business/GetShowBusiness.ts | 25 ++++++ modulo5/case/src/business/RunnerBusiness.ts | 42 +++++++++ modulo5/case/src/business/ShowBusiness.ts | 60 +++++++++++++ modulo5/case/src/business/UserBusiness.ts | 75 ++++++++++++++++ .../src/controller/GetDetailsController.ts | 24 +++++ .../case/src/controller/GetShowController.ts | 24 +++++ .../case/src/controller/RunnerController.ts | 40 +++++++++ modulo5/case/src/controller/ShowController.ts | 40 +++++++++ modulo5/case/src/controller/UserController.ts | 63 +++++++++++++ modulo5/case/src/data/BandDatabase.ts | 52 +++++++++++ modulo5/case/src/data/BaseDatabase.ts | 21 +++++ modulo5/case/src/data/RunnerDatabase.ts | 42 +++++++++ modulo5/case/src/data/ShowDatabase.ts | 54 +++++++++++ modulo5/case/src/error/BaseError.ts | 5 ++ modulo5/case/src/index.ts | 23 +++++ modulo5/case/src/model/Athlete.ts | 90 +++++++++++++++++++ modulo5/case/src/model/Runner.ts | 53 +++++++++++ modulo5/case/src/model/Show.ts | 49 ++++++++++ modulo5/case/src/routes/runnerRouter.ts | 12 +++ modulo5/case/src/routes/showRouter.ts | 12 +++ modulo5/case/src/routes/userRouter.ts | 10 +++ modulo5/case/src/services/Authenticator.ts | 32 +++++++ modulo5/case/src/services/HashManager.ts | 17 ++++ modulo5/case/src/services/IdGenerator.ts | 8 ++ modulo5/case/src/services/TokenGenerator.ts | 34 +++++++ modulo5/case/tests/band.test.ts | 55 ++++++++++++ modulo5/case/tsconfig.json | 15 ++++ 33 files changed, 1136 insertions(+) create mode 100644 modulo5/case/.gitignore create mode 100644 modulo5/case/Migrations.ts create mode 100644 modulo5/case/README.md create mode 100644 modulo5/case/jest.config.js create mode 100644 modulo5/case/package.json create mode 100644 modulo5/case/src/business/GetDetailsBusiness.ts create mode 100644 modulo5/case/src/business/GetShowBusiness.ts create mode 100644 modulo5/case/src/business/RunnerBusiness.ts create mode 100644 modulo5/case/src/business/ShowBusiness.ts create mode 100644 modulo5/case/src/business/UserBusiness.ts create mode 100644 modulo5/case/src/controller/GetDetailsController.ts create mode 100644 modulo5/case/src/controller/GetShowController.ts create mode 100644 modulo5/case/src/controller/RunnerController.ts create mode 100644 modulo5/case/src/controller/ShowController.ts create mode 100644 modulo5/case/src/controller/UserController.ts create mode 100644 modulo5/case/src/data/BandDatabase.ts create mode 100644 modulo5/case/src/data/BaseDatabase.ts create mode 100644 modulo5/case/src/data/RunnerDatabase.ts create mode 100644 modulo5/case/src/data/ShowDatabase.ts create mode 100644 modulo5/case/src/error/BaseError.ts create mode 100644 modulo5/case/src/index.ts create mode 100644 modulo5/case/src/model/Athlete.ts create mode 100644 modulo5/case/src/model/Runner.ts create mode 100644 modulo5/case/src/model/Show.ts create mode 100644 modulo5/case/src/routes/runnerRouter.ts create mode 100644 modulo5/case/src/routes/showRouter.ts create mode 100644 modulo5/case/src/routes/userRouter.ts create mode 100644 modulo5/case/src/services/Authenticator.ts create mode 100644 modulo5/case/src/services/HashManager.ts create mode 100644 modulo5/case/src/services/IdGenerator.ts create mode 100644 modulo5/case/src/services/TokenGenerator.ts create mode 100644 modulo5/case/tests/band.test.ts create mode 100644 modulo5/case/tsconfig.json diff --git a/modulo5/case/.gitignore b/modulo5/case/.gitignore new file mode 100644 index 0000000..9ee73e0 --- /dev/null +++ b/modulo5/case/.gitignore @@ -0,0 +1,4 @@ +.env +node_modules +package-lock.json +build \ No newline at end of file diff --git a/modulo5/case/Migrations.ts b/modulo5/case/Migrations.ts new file mode 100644 index 0000000..30d4d19 --- /dev/null +++ b/modulo5/case/Migrations.ts @@ -0,0 +1,36 @@ +import {BaseDatabase} from "./src/data/BaseDatabase" + +export class Migrations extends BaseDatabase { + + migrations = async ( + + ) => { + await this.connection + .raw(` + CREATE TABLE IF NOT EXISTS Banda_Lama ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(255) UNIQUE NOT NULL, + music_genre VARCHAR(255) NOT NULL, + responsible VARCHAR(255) UNIQUE NOT NULL + ); + CREATE TABLE IF NOT EXISTS Show_Lama ( + id VARCHAR(255) PRIMARY KEY, + week_day VARCHAR(255) NOT NULL, + start_time INT NOT NULL, + end_time INT NOT NULL, + band_id VARCHAR(255) NOT NULL, + FOREIGN KEY(band_id) REFERENCES NOME_TABELA_BANDAS(id) + ); + CREATE TABLE IF NOT EXISTS User_Lama ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + role VARCHAR(255) NOT NULL DEFAULT "NORMAL" + ); + `) + .then(console.log) + .catch(console.log) +} + connection: any +} \ No newline at end of file diff --git a/modulo5/case/README.md b/modulo5/case/README.md new file mode 100644 index 0000000..8019076 --- /dev/null +++ b/modulo5/case/README.md @@ -0,0 +1,41 @@ +# Labenu Music Awards + +### Documentação postman: https://documenter.getpostman.com/view/19296396/UyxhonZD + +### Descrição: + +*Labenu Musical Awards*, um festival com várias bandas famosas para a formatura da turma e, no final, pode eleger a banda que mais gostaram! Permite o gerenciamento completo desses shows. +Utilizamos o LiveShare no VsCode para fazer todo o projeto. +
Para verifica-lo deve-se baixar o arquivo atraves do git clone e instalar as dependencias atraves do npm i + +### Funcionalidades: + +1. Cadastro +2. Login +3. Endpoint de registrar banda +4. Endpoint de visualização de detalhes sobre a banda +5. Endpoint de adicionar um show a um dia +6. Endpoint de pegar todos os shows de uma data + +## 🤝 Colaboradores + + + + + + +
+ + Foto da Grazielle
+ + Grazielle Martins + +
+
+ + foto victor github
+ + Victor Xavier + +
+
diff --git a/modulo5/case/jest.config.js b/modulo5/case/jest.config.js new file mode 100644 index 0000000..969c9b1 --- /dev/null +++ b/modulo5/case/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + roots: ["/tests"], + transform: { + "^.+\\.tsx?$": "ts-jest", + }, + testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], + }; \ No newline at end of file diff --git a/modulo5/case/package.json b/modulo5/case/package.json new file mode 100644 index 0000000..bef2b24 --- /dev/null +++ b/modulo5/case/package.json @@ -0,0 +1,46 @@ +{ + "name": "vaughan-lama1", + "version": "1.0.0", + "description": "Como você deve saber muito bem, o nosso querido chefinho Astrodev é uma pessoa com Networking incrível e ele conhece vários artistas estrelados. Além disso, ele também é um grande ~~megalomaníaco~~ visionário e está planejando fazer um grande evento: o **LAMA**, *Labenu Musical Awards*, um festival com várias bandas famosas para a formatura da sua turma e, no final, vocês podem eleger a banda que mais gostaram! Entretanto, na opinião dele, vocês só serão merecedores se entregarem um sistema impecável que permita o gerenciamento completo desses shows.", + "main": "index.js", + "scripts": { + "start": "node ./build/index.js", + "dev": "ts-node-dev ./src/index.ts", + "tests": "node ./node_modules/jest/bin/jest.js", + "migrations": "tsnd Migrations.ts" + + }, + "repository": { + "type": "git", + "url": "git+https://github.com/future4code/vaughan-Victor-Xavier.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/future4code/vaughan-Victor-Xavier/issues" + }, + "homepage": "https://github.com/future4code/vaughan-Victor-Xavier#readme", + "dependencies": { + "@types/express": "^4.17.13", + "@types/jest": "^27.5.1", + "@types/jsonwebtoken": "^8.5.8", + "@types/knex": "^0.16.1", + "@types/node": "^17.0.32", + "bcryptjs": "^2.4.3", + "dotenv": "^16.0.1", + "express": "^4.18.1", + "jest": "^28.1.0", + "jsonwebtoken": "^8.5.1", + "knex": "^2.0.0", + "mysql": "^2.18.1", + "ts-jest": "^28.0.2", + "ts-node": "^10.7.0", + "ts-node-dev": "^1.1.8", + "typescript": "^4.6.4", + "uuid": "^8.3.2" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.2", + "@types/uuid": "^8.3.4" + } +} diff --git a/modulo5/case/src/business/GetDetailsBusiness.ts b/modulo5/case/src/business/GetDetailsBusiness.ts new file mode 100644 index 0000000..d6fc59a --- /dev/null +++ b/modulo5/case/src/business/GetDetailsBusiness.ts @@ -0,0 +1,24 @@ +import { BandDatabase } from "../data/BandDatabase"; +import { Authenticator } from "../services/Authenticator"; +import { HashManager } from "../services/HashManager"; + + +const bandDB = new BandDatabase(); + + +export class GetRunnerBusiness { + getBand = async (id: string) => { + try { + + const band = await bandDB.getBand(id) + if (!band) { + throw new Error("ID inválido") + } + return band + + + } catch (error: any) { + throw new Error(error.message); + } + } +} \ No newline at end of file diff --git a/modulo5/case/src/business/GetShowBusiness.ts b/modulo5/case/src/business/GetShowBusiness.ts new file mode 100644 index 0000000..2b50aa8 --- /dev/null +++ b/modulo5/case/src/business/GetShowBusiness.ts @@ -0,0 +1,25 @@ + +import { ShowDatabase } from "../data/ShowDatabase"; + + +const showDB = new ShowDatabase(); + + +export class GetShowBusiness { + getShow = async (show: string) => { + try { + + const getshow = await showDB.getShow(show) + + + if (getshow === undefined) { + throw new Error("Data inválida") + } + return getshow + + + } catch (error: any) { + throw new Error(error.message); + } + } +} \ No newline at end of file diff --git a/modulo5/case/src/business/RunnerBusiness.ts b/modulo5/case/src/business/RunnerBusiness.ts new file mode 100644 index 0000000..e2031a8 --- /dev/null +++ b/modulo5/case/src/business/RunnerBusiness.ts @@ -0,0 +1,42 @@ +import { IdGenerator } from "../services/IdGenerator" +import { RunnerInputDTO } from "../model/Runner" +import { HashManager } from "../services/HashManager"; +import { BandDatabase } from "../data/BandDatabase"; +import { Authenticator } from "../services/Authenticator"; +import { RunnerDatabase } from "../data/RunnerDatabase"; +import { TokenGenerator } from "../services/TokenGenerator"; + + +export class RunnerBusiness { + constructor( + private runnerDatabase: RunnerDatabase, + private idGenerator: IdGenerator, + private tokenGenerator: TokenGenerator, + private hashGenerator: HashManager + + ) { } + + async createRunner(band: RunnerInputDTO, token: string) { + + + + + const idGenerator = new IdGenerator(); + const id = idGenerator.generate(); + + const authenticator = new Authenticator(); + const tokenData = authenticator.getData(token); + + if (tokenData.role === "NORMAL") { + throw new Error("Role invalido"); + } + const bandDatabase = new BandDatabase(); + await bandDatabase.createBand(id, band.name, band.music_genre, band.responsible); + + + return tokenData; + } + + + +} \ No newline at end of file diff --git a/modulo5/case/src/business/ShowBusiness.ts b/modulo5/case/src/business/ShowBusiness.ts new file mode 100644 index 0000000..a48335a --- /dev/null +++ b/modulo5/case/src/business/ShowBusiness.ts @@ -0,0 +1,60 @@ +import { ShowDatabase } from "../data/ShowDatabase"; +import { UserDatabase } from "../data/RunnerDatabase"; +import { ShowInputDTO } from "../model/Show"; +import { showRouter } from "../routes/showRouter"; +import { Authenticator } from "../services/Authenticator"; +import { HashManager } from "../services/HashManager"; +import { IdGenerator } from "../services/IdGenerator"; +import { TokenGenerator } from "../services/TokenGenerator"; + +export class ShowBusiness { + constructor( + private showDatabase: ShowDatabase, + private idGenerator: IdGenerator, + private tokenGenerator: TokenGenerator, + private hashGenerator: HashManager + + ) { } + + + + public async createShow(show: ShowInputDTO) { + + const arrayDias = ["SEXTA", "SABADO", "DOMINGO"] + + if (!arrayDias.includes(show.week_day)) { + throw new Error("Necessita inserir o dia entre sexta e domingo"); + } + + if (show.start_time < 8 || show.start_time > 23) { + throw new Error("Horário indisponível"); + } + if (!show.start_time) { + throw new Error("Precisa de um horário"); + } + if (!show.band_id) { + throw new Error("Id da banda inválido"); + } + if (!show.end_time) { + throw new Error("Horário indisponível"); + } + + const idGenerator = new IdGenerator(); + const id = idGenerator.generate(); + + const authenticator = new Authenticator(); + const tokenData = authenticator.generateToken({ id }); + + const showDatabase = new ShowDatabase(); + const newshow = showDatabase.findByDayAndHours(show.week_day, show.start_time); + if ( (await newshow).length > 0) { + throw new Error("Dia ou Horário já utilizado") + } + + + await showDatabase.createShow(id, show.week_day, show.start_time, show.end_time, show.band_id) + + + return tokenData; + } +} diff --git a/modulo5/case/src/business/UserBusiness.ts b/modulo5/case/src/business/UserBusiness.ts new file mode 100644 index 0000000..ffe5d68 --- /dev/null +++ b/modulo5/case/src/business/UserBusiness.ts @@ -0,0 +1,75 @@ +import { UserInputDTO, LoginInputDTO } from "../model/Athlete"; +import { UserDatabase } from "../data/RunnerDatabase"; +import { IdGenerator } from "../services/IdGenerator"; +import { HashManager } from "../services/HashManager"; +import { Authenticator } from "../services/Authenticator"; +import { TokenGenerator } from "../services/TokenGenerator"; + +export class UserBusiness { + + constructor( + private userDatabase: UserDatabase, + private idGenerator:IdGenerator, + private tokenGenerator: TokenGenerator, + private hashGenerator: HashManager + + ){} + + public async createUser(user: UserInputDTO) { + + // if (!name) { + // throw new Error("Preencha o campo 'name'"); + // } + // if (!email) { + // throw new Error("Preencha o campo 'email'"); + // } + // if (!password) { + // throw new Error("Preencha o campo 'password'"); + // } + // if (!role) { + // throw new Error("Preencha o campo 'role'"); + // } + + if (user.password.length < 6) { + throw new Error("A senha deve conter no minimo 6 caracteres") + } + if (user.email.indexOf("@") === -1) { + throw new Error("Email invalido"); + } + + + + const idGenerator = new IdGenerator(); + const id = idGenerator.generate(); + + const hashManager = new HashManager(); + const hashPassword = await hashManager.hash(user.password); + + const userDatabase = new UserDatabase(); + await userDatabase.createUser(id, user.email, user.name, hashPassword, user.role); + + const authenticator = new Authenticator(); + const accessToken = authenticator.generateToken({ id, role: user.role }); + + return accessToken; + } + + public async getUserByEmail(user: LoginInputDTO) { + + const userDatabase = new UserDatabase(); + const userFromDB = await userDatabase.getUserByEmail(user.email); + + const hashManager = new HashManager(); + const hashCompare = await hashManager.compare(user.password, userFromDB.getPassword()); + + const authenticator = new Authenticator(); + const accessToken = authenticator.generateToken({ id: userFromDB.getId(), role: userFromDB.getRole() }); + + if (!hashCompare) { + throw new Error("Invalid Password!"); + } + + return accessToken; + } +} +export default UserBusiness; \ No newline at end of file diff --git a/modulo5/case/src/controller/GetDetailsController.ts b/modulo5/case/src/controller/GetDetailsController.ts new file mode 100644 index 0000000..2c6fca6 --- /dev/null +++ b/modulo5/case/src/controller/GetDetailsController.ts @@ -0,0 +1,24 @@ + +import { Request, Response } from 'express'; +import { GetRunnerBusiness} from '../business/GetDetailsBusiness'; + +const getbandBusiness = new GetRunnerBusiness() +export class GetRunnerController { + getBand = async (req: Request, res: Response) => { + + + try { + + const id = req.params.id + + + const band = await getbandBusiness.getBand(id); + + res.status(200).send({ band }); + + } catch (error: any) { + res.status(400).send({ error: error.message }); + } + + } +} \ No newline at end of file diff --git a/modulo5/case/src/controller/GetShowController.ts b/modulo5/case/src/controller/GetShowController.ts new file mode 100644 index 0000000..6ebb051 --- /dev/null +++ b/modulo5/case/src/controller/GetShowController.ts @@ -0,0 +1,24 @@ + +import { Request, Response } from 'express'; +import { GetShowBusiness } from '../business/GetShowBusiness'; + +const getshowBusiness = new GetShowBusiness() +export class GetShowController { + getShow = async (req: Request, res: Response) => { + + + try { + + const dia = req.query.dia as string + + + const show = await getshowBusiness.getShow(dia); + + res.status(200).send({ show: show }); + + } catch (error: any) { + res.status(400).send({ error: error.message }); + } + + } +} \ No newline at end of file diff --git a/modulo5/case/src/controller/RunnerController.ts b/modulo5/case/src/controller/RunnerController.ts new file mode 100644 index 0000000..f923ab1 --- /dev/null +++ b/modulo5/case/src/controller/RunnerController.ts @@ -0,0 +1,40 @@ +import { RunnerBusiness } from './../business/RunnerBusiness'; +import { Request, Response } from "express"; +import { RunnerDatabase } from "../data/RunnerDatabase"; +import { RunnerInputDTO } from "../model/Runner"; +import { HashManager } from "../services/HashManager"; +import { IdGenerator } from "../services/IdGenerator"; +import { TokenGenerator } from "../services/TokenGenerator"; +import { BaseDatabase } from '../data/BaseDatabase'; + + +const runnerController = new RunnerBusiness( + new RunnerDatabase(), + new IdGenerator(), + new TokenGenerator(), + new HashManager(), + +) +export class RunnerController { + async signupRunner(req: Request, res: Response) { + try { + const token = req.headers.authorization as string + const input: RunnerInputDTO = { + name: req.body.name, + music_genre: req.body.music_genre, + responsible: req.body.responsible + } + + + const runner = await runnerController.createRunner(input ,token) + + res.status(200).send({message: "Banda cadastrada!", token: token }); + + } catch (error: any) { + res.status(400).send({ error: error.message }); + } + + await BaseDatabase.destroyConnection(); + } + +} \ No newline at end of file diff --git a/modulo5/case/src/controller/ShowController.ts b/modulo5/case/src/controller/ShowController.ts new file mode 100644 index 0000000..b17d9b3 --- /dev/null +++ b/modulo5/case/src/controller/ShowController.ts @@ -0,0 +1,40 @@ +import { Request, Response } from "express" +import { ShowInputDTO } from "../model/Show" +import { BaseError } from "../error/BaseError" +import { ShowBusiness } from "../business/ShowBusiness" +import { IdGenerator } from "../services/IdGenerator" +import {TokenGenerator} from "../services/TokenGenerator" +import { HashManager } from "../services/HashManager" +import { ShowDatabase } from "../data/ShowDatabase" + + +const showBusiness = new ShowBusiness( + + new ShowDatabase(), + new IdGenerator(), + new TokenGenerator(), + new HashManager(), + +) +export class ShowController { + async create(req: Request, res: Response) { + try { + + const input: ShowInputDTO = { + week_day: req.body.week_day, + start_time: req.body.start_time, + end_time: req.body.end_time, + band_id: req.body.band_id + } + + const result = await showBusiness.createShow(input) + res.send({ menssage: "Show Criado" }) + + + } catch (error) { + const err = error as BaseError + res.status(400).send({ error: err.message }) + + } + } +} \ No newline at end of file diff --git a/modulo5/case/src/controller/UserController.ts b/modulo5/case/src/controller/UserController.ts new file mode 100644 index 0000000..0b8da63 --- /dev/null +++ b/modulo5/case/src/controller/UserController.ts @@ -0,0 +1,63 @@ +import { Request, Response } from "express"; +import { UserInputDTO, LoginInputDTO } from "../model/Athlete"; +import { UserBusiness } from "../business/UserBusiness"; +import {BaseDatabase} from "../data/BaseDatabase"; +import { IdGenerator } from "../services/IdGenerator"; +import { HashManager } from "../services/HashManager"; +import { Authenticator } from "../services/Authenticator"; +import { UserDatabase } from "../data/RunnerDatabase"; +import { TokenGenerator } from "../services/TokenGenerator"; + +const userBusiness = new UserBusiness( + new UserDatabase(), + new IdGenerator(), + new TokenGenerator(), + new HashManager(), + +) +export class UserController { + async signup(req: Request, res: Response) { + try { + + const input: UserInputDTO = { + email: req.body.email, + name: req.body.name, + password: req.body.password, + role: req.body.role + } + + + const token = await userBusiness.createUser(input); + + res.status(200).send({message: "Usuário cadastrado!", token: token }); + + } catch (error: any) { + res.status(400).send({ error: error.message }); + } + + await BaseDatabase.destroyConnection(); + } + + async login(req: Request, res: Response) { + + try { + + const loginData: LoginInputDTO = { + email: req.body.email, + password: req.body.password + }; + + + const token = await userBusiness.getUserByEmail(loginData); + + res.status(200).send({ token }); + + } catch (error: any) { + res.status(400).send({ error: error.message }); + } + + await BaseDatabase.destroyConnection(); + } + +} +export default new UserController() \ No newline at end of file diff --git a/modulo5/case/src/data/BandDatabase.ts b/modulo5/case/src/data/BandDatabase.ts new file mode 100644 index 0000000..e280cc2 --- /dev/null +++ b/modulo5/case/src/data/BandDatabase.ts @@ -0,0 +1,52 @@ + +import { User } from "../model/Athlete"; +import { BaseDatabase } from "./BaseDatabase"; +import { Band } from "../model/Runner"; + +export class BandDatabase extends BaseDatabase { + + private static TABLE_NAME = "Banda_Lama"; + + public async createBand( + id: string, + name: string, + music_genre: string, + responsible: string, + + ): Promise { + try { + await BaseDatabase.connection() + .insert({ + id, + name, + music_genre, + responsible + }) + .into(BandDatabase.TABLE_NAME); + } catch (error: any) { + throw new Error(error.sqlMessage || error.message); + } + } + + public async getBandByEmail(email: string): Promise { + const result = await BaseDatabase.connection() + .select("*") + .from(BandDatabase.TABLE_NAME) + .where({ email }); + + return Band.toUserModel(result[0]); + } + + getBand = async ( + id: string + ) => { + const post = await BaseDatabase.connection('Banda_Lama').select( + "id", + "name", + "music_genre", + "responsible" + ).where({ id }) + return post[0] + } + +} \ No newline at end of file diff --git a/modulo5/case/src/data/BaseDatabase.ts b/modulo5/case/src/data/BaseDatabase.ts new file mode 100644 index 0000000..1d5f6bb --- /dev/null +++ b/modulo5/case/src/data/BaseDatabase.ts @@ -0,0 +1,21 @@ +import knex from 'knex' +import dotenv from 'dotenv' + +dotenv.config() + +export abstract class BaseDatabase{ + protected static 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 + } + }) + public static async destroyConnection(): Promise { + await BaseDatabase.connection.destroy(); + } +} \ No newline at end of file diff --git a/modulo5/case/src/data/RunnerDatabase.ts b/modulo5/case/src/data/RunnerDatabase.ts new file mode 100644 index 0000000..ac50d1b --- /dev/null +++ b/modulo5/case/src/data/RunnerDatabase.ts @@ -0,0 +1,42 @@ + +import { Athlete } from "../model/Athlete"; +import { BaseDatabase } from "./BaseDatabase"; + +export class RunnerDatabase extends BaseDatabase { + + private static TABLE_NAME = "Athlete_CoeCase "; + + public async createAthlete( + id: string, + competition: string, + athlete: string, + value: string, + unity: string, + role: string + ): Promise { + try { + await BaseDatabase.connection() + .insert({ + id, + competition, + athlete, + value, + unity, + role + }) + .into(RunnerDatabase.TABLE_NAME); + } catch (error: any) { + throw new Error(error.sqlMessage || error.message); + } + } + + public async getUserBycompetition(competition: string): Promise { + const result = await BaseDatabase.connection() + .select("*") + .from(RunnerDatabase.TABLE_NAME) + .where({ competition }); + + return Athlete.toUserModel(result[0]); + } + +} \ No newline at end of file diff --git a/modulo5/case/src/data/ShowDatabase.ts b/modulo5/case/src/data/ShowDatabase.ts new file mode 100644 index 0000000..10a12a2 --- /dev/null +++ b/modulo5/case/src/data/ShowDatabase.ts @@ -0,0 +1,54 @@ +import { Band } from "../model/Runner"; +import { Show } from "../model/Show"; +import { BaseDatabase } from "./BaseDatabase"; + +export class ShowDatabase extends BaseDatabase { + + private static TABLE_NAME = "Show_Lama" + private static TABLE_SHOWS_BAND = "Banda_Lama" + public async createShow( + id: string, + week_day: string, + start_time: number, + end_time: number, + band_id: string + ): Promise { + try { + await BaseDatabase.connection() + .insert({ + id, + week_day, + start_time, + end_time, + band_id + }) + .into(ShowDatabase.TABLE_NAME); + } catch (error: any) { + throw new Error(error.sqlMessage || error.message); + } + } + + public async findByDayAndHours(week_day: string, start_time: number): Promise { + + const shows = await BaseDatabase.connection(ShowDatabase.TABLE_NAME) + .select('*') + .where({ week_day: week_day, start_time: start_time }) + + return shows.map((show) => Show.toShowModel(show)); + } + public getShow = async ( + week_day: string + ) => { + const show = await BaseDatabase.connection('Show_Lama').select( + "Banda_Lama.name", "Banda_Lama.music_genre" + ) + .from(ShowDatabase.TABLE_NAME) + .join(ShowDatabase.TABLE_SHOWS_BAND, "Banda_Lama.id", "Show_Lama.band_id" ) + .orderBy("Show_Lama.start_time") + .where( "week_day", `${week_day}`) + + return show[0] + } + + +} \ No newline at end of file diff --git a/modulo5/case/src/error/BaseError.ts b/modulo5/case/src/error/BaseError.ts new file mode 100644 index 0000000..2974de7 --- /dev/null +++ b/modulo5/case/src/error/BaseError.ts @@ -0,0 +1,5 @@ +export abstract class BaseError extends Error { + constructor(message: string, public code: number) { + super(message); + } + } \ No newline at end of file diff --git a/modulo5/case/src/index.ts b/modulo5/case/src/index.ts new file mode 100644 index 0000000..7ebcf8c --- /dev/null +++ b/modulo5/case/src/index.ts @@ -0,0 +1,23 @@ +import dotenv from "dotenv"; +import {AddressInfo} from "net"; +import express from "express"; +import { userRouter } from "./routes/userRouter"; +import { bandRouter } from "./routes/runnerRouter"; +import { showRouter } from "./routes/showRouter"; +dotenv.config(); +const app = express(); + +app.use(express.json()); + +app.use("/user", userRouter); +app.use("/band", bandRouter); +app.use("/show", showRouter); + +const server = app.listen(3000, () => { + if (server) { + const address = server.address() as AddressInfo; + console.log(`Servidor rodando em http://localhost:${address.port}`); + } else { + console.error(`Falha ao rodar o servidor.`); + } + }); \ No newline at end of file diff --git a/modulo5/case/src/model/Athlete.ts b/modulo5/case/src/model/Athlete.ts new file mode 100644 index 0000000..6bc3517 --- /dev/null +++ b/modulo5/case/src/model/Athlete.ts @@ -0,0 +1,90 @@ +export class Athlete{ + constructor( + private id: string, + private competition: string, + private athlete: string, + private value: string, + private unity: string, + private role: AthleteRole + ){} + + getId(){ + return this.id; + } + + getName(){ + return this.competition + } + + getEmail(){ + return this.athlete; + } + + getPassword(){ + return this.value; + } + getUnity(){ + return this.unity; + } + + getRole(){ + return this.role; + } + + setId(id: string){ + this.id = id; + } + + setName(competition: string){ + this.competition = competition; + } + + setEmail(athlete: string){ + this.athlete = athlete; + } + + setPassword(value: string){ + this.value = value; + } + setUnity(unity: string){ + this.unity = unity; + } + + setRole(role: AthleteRole){ + this.role = role; + } + + static stringToAthleteRole(input: string): AthleteRole{ + switch (input) { + case "RUNNER": + return AthleteRole.RUNNER; + case "DART": + return AthleteRole.DART; + default: + throw new Error("Invalid user role"); + } + } + + static toUserModel(athlete: any): Athlete { + return new Athlete(athlete.id, athlete.competition, athlete.athlete, athlete.value,athlete.unity, athlete.stringToAthleteRole(athlete.role)); + } + + +} + +export interface UserInputDTO{ + email: string; + password: string; + name: string; + role: string; +} + +export interface LoginInputDTO{ + email: string; + password: string; +} + +export enum AthleteRole{ + RUNNER = "RUNNER", + DART = "DART" +} \ No newline at end of file diff --git a/modulo5/case/src/model/Runner.ts b/modulo5/case/src/model/Runner.ts new file mode 100644 index 0000000..b2efc91 --- /dev/null +++ b/modulo5/case/src/model/Runner.ts @@ -0,0 +1,53 @@ +export class Band { + constructor( + private id: string, + private name: string, + private music_genre: string, + private responsible: string + + ) { } + + getId() { + return this.id + } + + getMusicGender() { + return this.music_genre + } + + getName() { + return this.name + } + + getResponsible() { + return this.responsible + + } + + setId(id: string) { + this.id = id + } + + setName(name: string) { + this.name = name + } + + setMusicGenre(music_genre: string) { + this.music_genre = music_genre + } + + setResponsible(responsible: string) { + this.responsible = responsible + } + + static toUserModel(band: any): Band { + return new Band(band.id, band.name, band.music_genre, band.responsible); + } +} + +export interface RunnerInputDTO{ + name: string; + music_genre: string; + responsible: string; +} + diff --git a/modulo5/case/src/model/Show.ts b/modulo5/case/src/model/Show.ts new file mode 100644 index 0000000..f587a3c --- /dev/null +++ b/modulo5/case/src/model/Show.ts @@ -0,0 +1,49 @@ + +export interface ShowInputDTO { + + week_day: WeekDay, + start_time: number, + end_time: number, + band_id: string + + +} + +export enum WeekDay { + SEXTA = "SEXTA", + SABADO = "SABADO", + DOMINGO = "DOMINGO" +} + + +export class Show { + constructor( + + private id: string, + private week_day: string, + private start_time: number, + private end_time: number, + private band_id: string + + ) { } + getId() { + return this.id + } + + getWeekDay() { + return this.week_day + } + getStartTime() { + return this.start_time + } + + getEndTime() { + return this.end_time + } + getBandId() { + return this.band_id + } + static toShowModel(data: any): Show { + return new Show(data.id, data.week_day, data.start_time, data.end_time, data.band_id); + }; +} diff --git a/modulo5/case/src/routes/runnerRouter.ts b/modulo5/case/src/routes/runnerRouter.ts new file mode 100644 index 0000000..7c05554 --- /dev/null +++ b/modulo5/case/src/routes/runnerRouter.ts @@ -0,0 +1,12 @@ +import { RunnerController } from './../controller/RunnerController'; +import express from "express"; +import { GetRunnerController } from "../controller/GetDetailsController"; + + +export const bandRouter = express.Router(); + +const runnerController = new RunnerController(); +const runnerController2 = new GetRunnerController(); + +bandRouter.post("/signup/runner", runnerController.signupRunner); +bandRouter.get("/details/:id", runnerController2.getBand); \ No newline at end of file diff --git a/modulo5/case/src/routes/showRouter.ts b/modulo5/case/src/routes/showRouter.ts new file mode 100644 index 0000000..4833dc2 --- /dev/null +++ b/modulo5/case/src/routes/showRouter.ts @@ -0,0 +1,12 @@ +import express from "express"; +import { GetShowController } from "../controller/GetShowController"; +import { ShowController } from "../controller/ShowController"; + + +export const showRouter = express.Router(); + +const showController = new ShowController(); +const getshowController = new GetShowController(); + +showRouter.post("/signup", showController.create); +showRouter.get("/details", getshowController.getShow); \ No newline at end of file diff --git a/modulo5/case/src/routes/userRouter.ts b/modulo5/case/src/routes/userRouter.ts new file mode 100644 index 0000000..1b56d3a --- /dev/null +++ b/modulo5/case/src/routes/userRouter.ts @@ -0,0 +1,10 @@ +import express from "express"; +import { UserController } from "../controller/UserController"; + + +export const userRouter = express.Router(); + +const userController = new UserController(); + +userRouter.post("/signup", userController.signup); +userRouter.post("/login", userController.login); \ No newline at end of file diff --git a/modulo5/case/src/services/Authenticator.ts b/modulo5/case/src/services/Authenticator.ts new file mode 100644 index 0000000..4a859a0 --- /dev/null +++ b/modulo5/case/src/services/Authenticator.ts @@ -0,0 +1,32 @@ +import * as jwt from "jsonwebtoken"; + +export class Authenticator { + public generateToken(input: AuthenticationData, + expiresIn: string = process.env.ACCESS_TOKEN_EXPIRES_IN!): string { + const token = jwt.sign( + { + id: input.id, + role: input.role + }, + process.env.JWT_KEY as string, + { + expiresIn, + } + ); + return token; + } + + public getData(token: string): AuthenticationData { + const payload = jwt.verify(token, process.env.JWT_KEY as string) as any; + const result = { + id: payload.id, + role: payload.role + }; + return result; + } +} + +export interface AuthenticationData { + id: string; + role?: string; +} \ No newline at end of file diff --git a/modulo5/case/src/services/HashManager.ts b/modulo5/case/src/services/HashManager.ts new file mode 100644 index 0000000..45704fb --- /dev/null +++ b/modulo5/case/src/services/HashManager.ts @@ -0,0 +1,17 @@ +import * as bcrypt from "bcryptjs"; + + +export class HashManager { + + public async hash(text: string): Promise { + const rounds = 12; + const salt = await bcrypt.genSalt(rounds); + const result = await bcrypt.hash(text, salt); + return result; + } + + public async compare(text: string, hash: string): Promise{ + return await bcrypt.compare(text, hash); + } + +} \ No newline at end of file diff --git a/modulo5/case/src/services/IdGenerator.ts b/modulo5/case/src/services/IdGenerator.ts new file mode 100644 index 0000000..8dc2b8a --- /dev/null +++ b/modulo5/case/src/services/IdGenerator.ts @@ -0,0 +1,8 @@ +import { v4 } from "uuid"; + +export class IdGenerator{ + + generate(): string{ + return v4(); + } +} \ No newline at end of file diff --git a/modulo5/case/src/services/TokenGenerator.ts b/modulo5/case/src/services/TokenGenerator.ts new file mode 100644 index 0000000..1e212ba --- /dev/null +++ b/modulo5/case/src/services/TokenGenerator.ts @@ -0,0 +1,34 @@ +import * as jwt from "jsonwebtoken"; +import dotenv from "dotenv"; + +dotenv.config(); + +export class TokenGenerator { + private static expiresIn: number = 1200; + + public generate = (input: AuthenticationData): string => { + const newToken = jwt.sign( + { + id: input.id, + role: input.role, + }, + process.env.JWT_KEY as string, + { + expiresIn: TokenGenerator.expiresIn, + } + ); + return newToken; + }; + + public verify(token: string) { + const payload = jwt.verify(token, process.env.JWT_KEY as string) as any; + const result = { id: payload.id, role: payload.role }; + return result; + } +} + +export interface AuthenticationData { + id: string; + role: string; +} + diff --git a/modulo5/case/tests/band.test.ts b/modulo5/case/tests/band.test.ts new file mode 100644 index 0000000..668ada5 --- /dev/null +++ b/modulo5/case/tests/band.test.ts @@ -0,0 +1,55 @@ +import { BandBusiness } from "../src/business/RunnerBusiness"; +import { BandInputDTO } from "../src/model/Runner"; +import { HashGeneratorMock } from "./mocks/hashGeneratorMock"; +import { IdGeneratorMock } from "./mocks/idGeneratorMock"; +import { TokenGeneratorMock } from "./mocks/tokenGeneratorMock"; +import { UserDatabaseMock } from "./mocks/userDatabaseMock"; + +const bandBusinessMock = new BandBusiness( + new UserDatabaseMock() as any, + new IdGeneratorMock(), + new TokenGeneratorMock(), + new HashGeneratorMock() +) +export const validarBanda = (input: BandInputDTO): boolean => { + if (!input.name === undefined || input.music_genre === undefined || input.responsible === undefined) { + return false + } + + return true +}; +describe("Testando o cadastro da banda sem erro", () => { + + test("com nome", async () => { + + expect.assertions + try { + const novaBanda = validarBanda({ + name: "abc", + music_genre:"aaa", + responsible: "ssss" + }); + expect(novaBanda).toBe(true); + } catch (error: any) { + + expect(error.message).toBe("Banda inválida") + } + }) + +}); + +describe("Testando o cadastro da banda com erro", () => { + + test("sem nome", async () => { + + expect.assertions + + const novaBanda = validarBanda({ + name: "aewew", + music_genre:"", + responsible: "ssss" + }); + expect(novaBanda).toBeDefined(); + + }) +}); diff --git a/modulo5/case/tsconfig.json b/modulo5/case/tsconfig.json new file mode 100644 index 0000000..0807d5d --- /dev/null +++ b/modulo5/case/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "sourceMap": true, + "outDir": "./build", + "rootDir": "./", + "removeComments": true, + "strict": true, + "noImplicitAny": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true + + } + } \ No newline at end of file From 0d87f8872df20a763c8b79bf0c8e7a9af5211768 Mon Sep 17 00:00:00 2001 From: Vsux Date: Tue, 17 May 2022 12:17:20 -0200 Subject: [PATCH 2/6] teste 2 --- modulo5/case/package.json | 10 +- modulo5/case/src/business/ShowBusiness.ts | 1 - modulo5/case/src/business/UserBusiness.ts | 116 +++++++++--------- modulo5/case/src/controller/UserController.ts | 94 +++++++------- modulo5/case/src/data/BandDatabase.ts | 2 +- modulo5/case/src/routes/userRouter.ts | 8 +- modulo5/case/tests/band.test.ts | 88 ++++++------- 7 files changed, 159 insertions(+), 160 deletions(-) diff --git a/modulo5/case/package.json b/modulo5/case/package.json index bef2b24..be82a07 100644 --- a/modulo5/case/package.json +++ b/modulo5/case/package.json @@ -4,11 +4,11 @@ "description": "Como você deve saber muito bem, o nosso querido chefinho Astrodev é uma pessoa com Networking incrível e ele conhece vários artistas estrelados. Além disso, ele também é um grande ~~megalomaníaco~~ visionário e está planejando fazer um grande evento: o **LAMA**, *Labenu Musical Awards*, um festival com várias bandas famosas para a formatura da sua turma e, no final, vocês podem eleger a banda que mais gostaram! Entretanto, na opinião dele, vocês só serão merecedores se entregarem um sistema impecável que permita o gerenciamento completo desses shows.", "main": "index.js", "scripts": { - "start": "node ./build/index.js", - "dev": "ts-node-dev ./src/index.ts", - "tests": "node ./node_modules/jest/bin/jest.js", - "migrations": "tsnd Migrations.ts" - + "start:dev": "ts-node-dev ./src/index.ts", + "start": "tsc && node ./build/index.js", + "build": "tsc", + "dev": "ts-node-dev ./src/index.ts" + }, "repository": { "type": "git", diff --git a/modulo5/case/src/business/ShowBusiness.ts b/modulo5/case/src/business/ShowBusiness.ts index a48335a..9df6a5e 100644 --- a/modulo5/case/src/business/ShowBusiness.ts +++ b/modulo5/case/src/business/ShowBusiness.ts @@ -1,5 +1,4 @@ import { ShowDatabase } from "../data/ShowDatabase"; -import { UserDatabase } from "../data/RunnerDatabase"; import { ShowInputDTO } from "../model/Show"; import { showRouter } from "../routes/showRouter"; import { Authenticator } from "../services/Authenticator"; diff --git a/modulo5/case/src/business/UserBusiness.ts b/modulo5/case/src/business/UserBusiness.ts index ffe5d68..617ec2e 100644 --- a/modulo5/case/src/business/UserBusiness.ts +++ b/modulo5/case/src/business/UserBusiness.ts @@ -1,75 +1,75 @@ -import { UserInputDTO, LoginInputDTO } from "../model/Athlete"; -import { UserDatabase } from "../data/RunnerDatabase"; -import { IdGenerator } from "../services/IdGenerator"; -import { HashManager } from "../services/HashManager"; -import { Authenticator } from "../services/Authenticator"; -import { TokenGenerator } from "../services/TokenGenerator"; - -export class UserBusiness { - - constructor( - private userDatabase: UserDatabase, - private idGenerator:IdGenerator, - private tokenGenerator: TokenGenerator, - private hashGenerator: HashManager +// import { UserInputDTO, LoginInputDTO } from "../model/Athlete"; +// import { RunnerDatabase } from "../data/RunnerDatabase"; +// import { IdGenerator } from "../services/IdGenerator"; +// import { HashManager } from "../services/HashManager"; +// import { Authenticator } from "../services/Authenticator"; +// import { TokenGenerator } from "../services/TokenGenerator"; + +// export class UserBusiness { + +// constructor( +// private runnerDatabase: RunnerDatabase, +// private idGenerator:IdGenerator, +// private tokenGenerator: TokenGenerator, +// private hashGenerator: HashManager - ){} +// ){} - public async createUser(user: UserInputDTO) { +// public async createUser(user: UserInputDTO) { - // if (!name) { - // throw new Error("Preencha o campo 'name'"); - // } - // if (!email) { - // throw new Error("Preencha o campo 'email'"); - // } - // if (!password) { - // throw new Error("Preencha o campo 'password'"); - // } - // if (!role) { - // throw new Error("Preencha o campo 'role'"); - // } +// // if (!name) { +// // throw new Error("Preencha o campo 'name'"); +// // } +// // if (!email) { +// // throw new Error("Preencha o campo 'email'"); +// // } +// // if (!password) { +// // throw new Error("Preencha o campo 'password'"); +// // } +// // if (!role) { +// // throw new Error("Preencha o campo 'role'"); +// // } - if (user.password.length < 6) { - throw new Error("A senha deve conter no minimo 6 caracteres") - } - if (user.email.indexOf("@") === -1) { - throw new Error("Email invalido"); - } +// if (user.password.length < 6) { +// throw new Error("A senha deve conter no minimo 6 caracteres") +// } +// if (user.email.indexOf("@") === -1) { +// throw new Error("Email invalido"); +// } - const idGenerator = new IdGenerator(); - const id = idGenerator.generate(); +// const idGenerator = new IdGenerator(); +// const id = idGenerator.generate(); - const hashManager = new HashManager(); - const hashPassword = await hashManager.hash(user.password); +// const hashManager = new HashManager(); +// const hashPassword = await hashManager.hash(user.password); - const userDatabase = new UserDatabase(); - await userDatabase.createUser(id, user.email, user.name, hashPassword, user.role); +// const userDatabase = new RunnerDatabase(); +// await userDatabase.createRunner(id, user.email, user.name, hashPassword, user.role); - const authenticator = new Authenticator(); - const accessToken = authenticator.generateToken({ id, role: user.role }); +// const authenticator = new Authenticator(); +// const accessToken = authenticator.generateToken({ id, role: user.role }); - return accessToken; - } +// return accessToken; +// } - public async getUserByEmail(user: LoginInputDTO) { +// public async getUserByEmail(user: LoginInputDTO) { - const userDatabase = new UserDatabase(); - const userFromDB = await userDatabase.getUserByEmail(user.email); +// const userDatabase = new UserDatabase(); +// const userFromDB = await userDatabase.getUserByEmail(user.email); - const hashManager = new HashManager(); - const hashCompare = await hashManager.compare(user.password, userFromDB.getPassword()); +// const hashManager = new HashManager(); +// const hashCompare = await hashManager.compare(user.password, userFromDB.getPassword()); - const authenticator = new Authenticator(); - const accessToken = authenticator.generateToken({ id: userFromDB.getId(), role: userFromDB.getRole() }); +// const authenticator = new Authenticator(); +// const accessToken = authenticator.generateToken({ id: userFromDB.getId(), role: userFromDB.getRole() }); - if (!hashCompare) { - throw new Error("Invalid Password!"); - } +// if (!hashCompare) { +// throw new Error("Invalid Password!"); +// } - return accessToken; - } -} -export default UserBusiness; \ No newline at end of file +// return accessToken; +// } +// } +// export default UserBusiness; \ No newline at end of file diff --git a/modulo5/case/src/controller/UserController.ts b/modulo5/case/src/controller/UserController.ts index 0b8da63..b3c769d 100644 --- a/modulo5/case/src/controller/UserController.ts +++ b/modulo5/case/src/controller/UserController.ts @@ -1,63 +1,63 @@ -import { Request, Response } from "express"; -import { UserInputDTO, LoginInputDTO } from "../model/Athlete"; -import { UserBusiness } from "../business/UserBusiness"; -import {BaseDatabase} from "../data/BaseDatabase"; -import { IdGenerator } from "../services/IdGenerator"; -import { HashManager } from "../services/HashManager"; -import { Authenticator } from "../services/Authenticator"; -import { UserDatabase } from "../data/RunnerDatabase"; -import { TokenGenerator } from "../services/TokenGenerator"; - -const userBusiness = new UserBusiness( - new UserDatabase(), - new IdGenerator(), - new TokenGenerator(), - new HashManager(), +// import { Request, Response } from "express"; +// import { UserInputDTO, LoginInputDTO } from "../model/Athlete"; + +// import {BaseDatabase} from "../data/BaseDatabase"; +// import { IdGenerator } from "../services/IdGenerator"; +// import { HashManager } from "../services/HashManager"; +// import { Authenticator } from "../services/Authenticator"; +// import { RunnerDatabase } from "../data/RunnerDatabase"; +// import { TokenGenerator } from "../services/TokenGenerator"; + +// const runnerBusiness = new RunnerBusiness( +// new RunnerDatabase(), +// new IdGenerator(), +// new TokenGenerator(), +// new HashManager(), -) -export class UserController { - async signup(req: Request, res: Response) { - try { +// ) +// export class RunnerController { +// async signup(req: Request, res: Response) { +// try { - const input: UserInputDTO = { - email: req.body.email, - name: req.body.name, - password: req.body.password, - role: req.body.role - } +// const input: UserInputDTO = { +// email: req.body.email, +// name: req.body.name, +// password: req.body.password, +// role: req.body.role +// } - const token = await userBusiness.createUser(input); +// const token = await runnerBusiness.createUser(input); - res.status(200).send({message: "Usuário cadastrado!", token: token }); +// res.status(200).send({message: "Usuário cadastrado!", token: token }); - } catch (error: any) { - res.status(400).send({ error: error.message }); - } +// } catch (error: any) { +// res.status(400).send({ error: error.message }); +// } - await BaseDatabase.destroyConnection(); - } +// await BaseDatabase.destroyConnection(); +// } - async login(req: Request, res: Response) { +// async login(req: Request, res: Response) { - try { +// try { - const loginData: LoginInputDTO = { - email: req.body.email, - password: req.body.password - }; +// const loginData: LoginInputDTO = { +// email: req.body.email, +// password: req.body.password +// }; - const token = await userBusiness.getUserByEmail(loginData); +// const token = await runnerBusiness.getUserByEmail(loginData); - res.status(200).send({ token }); +// res.status(200).send({ token }); - } catch (error: any) { - res.status(400).send({ error: error.message }); - } +// } catch (error: any) { +// res.status(400).send({ error: error.message }); +// } - await BaseDatabase.destroyConnection(); - } +// await BaseDatabase.destroyConnection(); +// } -} -export default new UserController() \ No newline at end of file +// } +// export default new UserController() \ No newline at end of file diff --git a/modulo5/case/src/data/BandDatabase.ts b/modulo5/case/src/data/BandDatabase.ts index e280cc2..af86ff7 100644 --- a/modulo5/case/src/data/BandDatabase.ts +++ b/modulo5/case/src/data/BandDatabase.ts @@ -1,5 +1,5 @@ -import { User } from "../model/Athlete"; +import { Athlete } from "../model/Athlete"; import { BaseDatabase } from "./BaseDatabase"; import { Band } from "../model/Runner"; diff --git a/modulo5/case/src/routes/userRouter.ts b/modulo5/case/src/routes/userRouter.ts index 1b56d3a..ccd2b7b 100644 --- a/modulo5/case/src/routes/userRouter.ts +++ b/modulo5/case/src/routes/userRouter.ts @@ -1,10 +1,10 @@ import express from "express"; -import { UserController } from "../controller/UserController"; +import { RunnerController } from "../controller/RunnerController"; export const userRouter = express.Router(); -const userController = new UserController(); +const userController = new RunnerController(); -userRouter.post("/signup", userController.signup); -userRouter.post("/login", userController.login); \ No newline at end of file +userRouter.post("/signup", userController.signupRunner); +// userRouter.post("/login", userController.login); \ No newline at end of file diff --git a/modulo5/case/tests/band.test.ts b/modulo5/case/tests/band.test.ts index 668ada5..6565360 100644 --- a/modulo5/case/tests/band.test.ts +++ b/modulo5/case/tests/band.test.ts @@ -1,55 +1,55 @@ -import { BandBusiness } from "../src/business/RunnerBusiness"; -import { BandInputDTO } from "../src/model/Runner"; -import { HashGeneratorMock } from "./mocks/hashGeneratorMock"; -import { IdGeneratorMock } from "./mocks/idGeneratorMock"; -import { TokenGeneratorMock } from "./mocks/tokenGeneratorMock"; -import { UserDatabaseMock } from "./mocks/userDatabaseMock"; +// import { BandBusiness } from "../src/business/RunnerBusiness"; +// import { BandInputDTO } from "../src/model/Runner"; +// import { HashGeneratorMock } from "./mocks/hashGeneratorMock"; +// import { IdGeneratorMock } from "./mocks/idGeneratorMock"; +// import { TokenGeneratorMock } from "./mocks/tokenGeneratorMock"; +// import { UserDatabaseMock } from "./mocks/userDatabaseMock"; -const bandBusinessMock = new BandBusiness( - new UserDatabaseMock() as any, - new IdGeneratorMock(), - new TokenGeneratorMock(), - new HashGeneratorMock() -) -export const validarBanda = (input: BandInputDTO): boolean => { - if (!input.name === undefined || input.music_genre === undefined || input.responsible === undefined) { - return false - } +// const bandBusinessMock = new BandBusiness( +// new UserDatabaseMock() as any, +// new IdGeneratorMock(), +// new TokenGeneratorMock(), +// new HashGeneratorMock() +// ) +// export const validarBanda = (input: BandInputDTO): boolean => { +// if (!input.name === undefined || input.music_genre === undefined || input.responsible === undefined) { +// return false +// } - return true -}; -describe("Testando o cadastro da banda sem erro", () => { +// return true +// }; +// describe("Testando o cadastro da banda sem erro", () => { - test("com nome", async () => { +// test("com nome", async () => { - expect.assertions - try { - const novaBanda = validarBanda({ - name: "abc", - music_genre:"aaa", - responsible: "ssss" - }); - expect(novaBanda).toBe(true); - } catch (error: any) { +// expect.assertions +// try { +// const novaBanda = validarBanda({ +// name: "abc", +// music_genre:"aaa", +// responsible: "ssss" +// }); +// expect(novaBanda).toBe(true); +// } catch (error: any) { - expect(error.message).toBe("Banda inválida") - } - }) +// expect(error.message).toBe("Banda inválida") +// } +// }) -}); +// }); -describe("Testando o cadastro da banda com erro", () => { +// describe("Testando o cadastro da banda com erro", () => { - test("sem nome", async () => { +// test("sem nome", async () => { - expect.assertions +// expect.assertions - const novaBanda = validarBanda({ - name: "aewew", - music_genre:"", - responsible: "ssss" - }); - expect(novaBanda).toBeDefined(); +// const novaBanda = validarBanda({ +// name: "aewew", +// music_genre:"", +// responsible: "ssss" +// }); +// expect(novaBanda).toBeDefined(); - }) -}); +// }) +// }); From 8a1d22e89692896a62431b2ddabc1665150ee8d3 Mon Sep 17 00:00:00 2001 From: Vsux Date: Thu, 19 May 2022 17:05:04 -0200 Subject: [PATCH 3/6] finalizado sem os testes --- modulo5/case-estante-coe/.gitignore | 4 + modulo5/case-estante-coe/README.md | 0 modulo5/case-estante-coe/jest.config.js | 8 ++ modulo5/case-estante-coe/package.json | 21 ++++ .../DartCompetitionBusiness.ts | 93 +++++++++++++++ .../DartCompetitionRepository.ts | 12 ++ .../RunnerCompetition/RunnerBusiness.ts | 91 ++++++++++++++ .../RunnerCompetitionRepository.ts | 12 ++ .../Controller/DartCompetitionController.ts | 64 ++++++++++ .../src/Controller/RunnerController.ts | 62 ++++++++++ .../case-estante-coe/src/Data/BaseDatabase.ts | 21 ++++ .../src/Data/DartCompetitionDatabase.ts | 111 ++++++++++++++++++ .../src/Data/RunnerDatabase.ts | 108 +++++++++++++++++ .../case-estante-coe/src/Model/Competition.ts | 59 ++++++++++ .../case-estante-coe/src/Routes/dartRouter.ts | 9 ++ .../src/Routes/runnerRouter.ts | 9 ++ .../src/Services/Authenticator.ts | 32 +++++ .../src/Services/HashManager.ts | 17 +++ .../src/Services/IdGeneretor.ts | 7 ++ .../src/Services/TokenGenerator.ts | 34 ++++++ modulo5/case-estante-coe/src/index.ts | 22 ++++ modulo5/case-estante-coe/tsconfig.json | 101 ++++++++++++++++ 22 files changed, 897 insertions(+) create mode 100644 modulo5/case-estante-coe/.gitignore create mode 100644 modulo5/case-estante-coe/README.md create mode 100644 modulo5/case-estante-coe/jest.config.js create mode 100644 modulo5/case-estante-coe/package.json create mode 100644 modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionBusiness.ts create mode 100644 modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionRepository.ts create mode 100644 modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerBusiness.ts create mode 100644 modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerCompetitionRepository.ts create mode 100644 modulo5/case-estante-coe/src/Controller/DartCompetitionController.ts create mode 100644 modulo5/case-estante-coe/src/Controller/RunnerController.ts create mode 100644 modulo5/case-estante-coe/src/Data/BaseDatabase.ts create mode 100644 modulo5/case-estante-coe/src/Data/DartCompetitionDatabase.ts create mode 100644 modulo5/case-estante-coe/src/Data/RunnerDatabase.ts create mode 100644 modulo5/case-estante-coe/src/Model/Competition.ts create mode 100644 modulo5/case-estante-coe/src/Routes/dartRouter.ts create mode 100644 modulo5/case-estante-coe/src/Routes/runnerRouter.ts create mode 100644 modulo5/case-estante-coe/src/Services/Authenticator.ts create mode 100644 modulo5/case-estante-coe/src/Services/HashManager.ts create mode 100644 modulo5/case-estante-coe/src/Services/IdGeneretor.ts create mode 100644 modulo5/case-estante-coe/src/Services/TokenGenerator.ts create mode 100644 modulo5/case-estante-coe/src/index.ts create mode 100644 modulo5/case-estante-coe/tsconfig.json diff --git a/modulo5/case-estante-coe/.gitignore b/modulo5/case-estante-coe/.gitignore new file mode 100644 index 0000000..8ece3ba --- /dev/null +++ b/modulo5/case-estante-coe/.gitignore @@ -0,0 +1,4 @@ +node_modules +package-lock.json +build +.env \ No newline at end of file diff --git a/modulo5/case-estante-coe/README.md b/modulo5/case-estante-coe/README.md new file mode 100644 index 0000000..e69de29 diff --git a/modulo5/case-estante-coe/jest.config.js b/modulo5/case-estante-coe/jest.config.js new file mode 100644 index 0000000..2ff86e1 --- /dev/null +++ b/modulo5/case-estante-coe/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + roots: ["/tests"], + transform: { + "^.+\\.tsx?$": "ts-jest", + }, + testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], +}; \ No newline at end of file diff --git a/modulo5/case-estante-coe/package.json b/modulo5/case-estante-coe/package.json new file mode 100644 index 0000000..52b11ef --- /dev/null +++ b/modulo5/case-estante-coe/package.json @@ -0,0 +1,21 @@ +{ + "name": "case1", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start:dev": "ts-node-dev ./src/index.ts", + "start": "tsc && node ./build/index.js", + "build": "tsc", + "dev": "ts-node-dev ./src/index.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "bcryptjs": "^2.4.3", + "dotenv": "^16.0.1", + "jsonwebtoken": "^8.5.1", + "typescript": "^4.6.4" + } +} diff --git a/modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionBusiness.ts b/modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionBusiness.ts new file mode 100644 index 0000000..171888e --- /dev/null +++ b/modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionBusiness.ts @@ -0,0 +1,93 @@ +import { Competition, InputDTO, Progretion } from "../../Model/Competition"; +import { IdGenerator } from "../../Services/IdGeneretor"; +import { DartCompetitionRepository } from "./DartCompetitionRepository"; + +export default class DartCompetitionBusiness { + private idGenerator: IdGenerator; + private competitionData: DartCompetitionRepository; + + constructor( + competitionDataImplementation: DartCompetitionRepository + ) { + this.idGenerator = new IdGenerator + this.competitionData = competitionDataImplementation + } + + insertDart = async (input: InputDTO) => { + const { athlete, competition, unity, valor } = input + + if (!competition || !athlete || !valor || !unity) { + throw new Error("Preencha todos os campos") + } + + if (typeof competition !== "string" || typeof athlete !== "string" || typeof valor !== "string" || typeof unity !== "string") { + throw new Error("Preencha valores válidos") + } + + if (unity !== "m") { + throw new Error("unity inválida!") + } + + const verificaProgretionCompetition = await this.competitionData.getSituationByName(competition, Progretion.FINISH) + + if (verificaProgretionCompetition?.length > 0) { + throw new Error("Competição finalizada.") + } + + const verificaChances = await this.competitionData.getAthleteCount(athlete, competition) + + if (verificaChances >= 3) { + throw new Error("O athlete já realizou todos os lançamentos!") + } + + if (unity !== "m") { + throw new Error("unity inválida!") + } + + const id = this.idGenerator.generate() + + const progretion = Progretion.PROGRESS + + const novacompetition = new Competition( + id, + competition, + athlete, + valor, + unity, + progretion + ) + + await this.competitionData.insert(novacompetition) + + + } + + finishDart = async (input: string) => { + const competition = input + + const progretion = Progretion.FINISH + + const verifyCompetition = await this.competitionData.getCompetitionByName(competition) + + if (!verifyCompetition) { + throw new Error("Competição ou modalidade não existente.") + } + + await this.competitionData.updateSituation(progretion, competition) + } + + getRanking = async (input: string) => { + const competition = input + + const verificacompetition = await this.competitionData.getCompetitionByName(competition) + + if (!verificacompetition) { + throw new Error("Competição ou modalidade não existente") + + } + + const resultado = await this.competitionData.getRanking(competition) + + return resultado + } +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionRepository.ts b/modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionRepository.ts new file mode 100644 index 0000000..cad133c --- /dev/null +++ b/modulo5/case-estante-coe/src/Business/DartCompetition/DartCompetitionRepository.ts @@ -0,0 +1,12 @@ +import { Competition, Progretion } from "../../Model/Competition" + +export interface DartCompetitionRepository { + insert(competition: Competition): Promise + getByAthlete(athlete: string): Promise + getCompetitionByName(competition: string): Promise + updateSituation(situation: Progretion.FINISH, competition: string): Promise + getSituationByName(competition: string, situation: Progretion.FINISH): Promise + getCompetitionAndAthlete(competition: string): Promise + getRanking(competition: string): Promise + getAthleteCount(athlete: string, competition: string): Promise +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerBusiness.ts b/modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerBusiness.ts new file mode 100644 index 0000000..289beef --- /dev/null +++ b/modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerBusiness.ts @@ -0,0 +1,91 @@ +import { Competition, InputDTO, Progretion } from "../../Model/Competition"; +import { IdGenerator } from "../../Services/IdGeneretor"; +import { RunnerCompetitionRepository } from "./RunnerCompetitionRepository"; + + +export class RunnerCompetitionBusiness { + private idGenerator: IdGenerator; + private competitionData: RunnerCompetitionRepository; + + constructor( + competitionDataImplementation: RunnerCompetitionRepository + ) { + this.idGenerator = new IdGenerator + this.competitionData = competitionDataImplementation + } + + insertRunner = async (input: InputDTO): Promise => { + const { athlete, competition, unity, valor } = input + + if (!competition || !athlete || !valor || !unity) { + throw new Error("Preencha todos os campos") + } + + if (typeof competition !== "string" || typeof athlete !== "string" || typeof valor !== "string" || typeof unity !== "string") { + throw new Error("Preencha valores válidos") + } + + if (unity !== "s") { + throw new Error("unity inválida!") + } + + const verificaProgretioncompetition = await this.competitionData.getSituationByName(competition, Progretion.FINISH) + + if (verificaProgretioncompetition.length > 0) { + throw new Error("Competição finalizada.") + } + + const verificaCompetidor = await this.competitionData.getByAthlete(athlete) + + if (verificaCompetidor) { + const verificaQualcompetition = await this.competitionData.getCompetitionAndAthlete(competition) + + if (verificaQualcompetition === athlete) { + throw new Error(" 'athlete' já realizou essa prova") + } + + const id = this.idGenerator.generate() + + const progretion = Progretion.PROGRESS + + const novacompetition = new Competition( + id, + competition, + athlete, + valor, + unity, + progretion + ) + + await this.competitionData.insert(novacompetition) + } + } + + finishRun = async (input: string) => { + const competition = input + + const progretion = Progretion.FINISH + + const verificacompetition = await this.competitionData.getCompetitionByName(competition) + + if (!verificacompetition) { + throw new Error("Competição ou modalidade não existente.") + } + + await this.competitionData.updateSituation(progretion, competition) + } + + getRanking = async (input: string) => { + const competition = input + + const verificacompetition = await this.competitionData.getCompetitionByName(competition) + + if (!verificacompetition) { + throw new Error("Competição ou modalidade não existente") + } + + const resultado = await this.competitionData.getRanking(competition) + + return resultado + } +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerCompetitionRepository.ts b/modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerCompetitionRepository.ts new file mode 100644 index 0000000..7981d44 --- /dev/null +++ b/modulo5/case-estante-coe/src/Business/RunnerCompetition/RunnerCompetitionRepository.ts @@ -0,0 +1,12 @@ +import { Competition, Progretion } from "../../Model/Competition"; + +export interface RunnerCompetitionRepository { + insert(competition: Competition): Promise + getByAthlete(athlete: string): Promise + getCompetitionByName(competition: string): Promise + updateSituation(situation: Progretion.FINISH, competition: string): Promise + getSituationByName(competition: string, situation: Progretion.FINISH): Promise + getCompetitionAndAthlete(competition: string): Promise + getRanking(competition: string): Promise + getAthleteCount(athlete: string, competition: string): Promise +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Controller/DartCompetitionController.ts b/modulo5/case-estante-coe/src/Controller/DartCompetitionController.ts new file mode 100644 index 0000000..c2f2bcf --- /dev/null +++ b/modulo5/case-estante-coe/src/Controller/DartCompetitionController.ts @@ -0,0 +1,64 @@ +import { Request, Response } from "express"; +import DartCompetitionBusiness from "../Business/DartCompetition/DartCompetitionBusiness"; +import { DartCompetitionDatabase } from "../Data/DartCompetitionDatabase"; + +import { InputDTO } from "../Model/Competition"; + + +export default class DartCompetitionController { + private dartCompetitionBusiness: DartCompetitionBusiness; + constructor( + ) { + this.dartCompetitionBusiness = new DartCompetitionBusiness(new DartCompetitionDatabase()) + } + + createDart = async (req: Request, res: Response) => { + const { competition, athlete, valor, unity } = req.body + + const input: InputDTO = { + competition, + athlete, + valor, + unity + } + + try { + await this.dartCompetitionBusiness.insertDart(input) + res.send({ message: `Atleta inscrito na competição ' ${competition}'` }) + + } catch (error: any) { + res.statusCode = 400 + let message = error.sqlMessage || error.message + res.send({ message }) + } + } + + finishDart = async (req: Request, res: Response) => { + const { competition } = req.body + + try { + await this.dartCompetitionBusiness.finishDart(competition) + res.send({ message: "Competição finalizada." }) + + } catch (error: any) { + res.statusCode = 400 + let message = error.sqlMessage || error.message + res.send({ message }) + } + } + + rankingDart = async (req: Request, res: Response) => { + const { competition } = req.body + + try { + const ranking = await this.dartCompetitionBusiness.getRanking(competition) + res.send({ message: "Resultado da competição", ranking }) + + } catch (error: any) { + res.statusCode = 400 + let message = error.sqlMessage || error.message + res.send({ message }) + } + } + +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Controller/RunnerController.ts b/modulo5/case-estante-coe/src/Controller/RunnerController.ts new file mode 100644 index 0000000..9754df2 --- /dev/null +++ b/modulo5/case-estante-coe/src/Controller/RunnerController.ts @@ -0,0 +1,62 @@ +import { RunnerCompetitionBusiness } from "../Business/RunnerCompetition/RunnerBusiness"; +import { InputDTO } from "../Model/Competition"; +import { Request, Response } from "express"; +import { RunnerDatabase } from "../Data/RunnerDatabase"; + +export class RunnerCompetitionController { + private runnerCompetitionBusiness: RunnerCompetitionBusiness; + constructor( + ) { + this.runnerCompetitionBusiness = new RunnerCompetitionBusiness(new RunnerDatabase()) + } + + createRunner = async (req: Request, res: Response) => { + const { competition, athlete, valor, unity } = req.body + + const input: InputDTO = { + competition, + athlete, + valor, + unity + } + + try { + await this.runnerCompetitionBusiness.insertRunner(input) + res.send({ message: "Atleta inscrito na competição" }) + + } catch (error: any) { + res.statusCode = 400 + let message = error.sqlMessage || error.message + res.send({ message }) + } + } + + finishRun = async (req: Request, res: Response) => { + const { competition } = req.body + + try { + await this.runnerCompetitionBusiness.finishRun(competition) + res.send({ message: "Competição finalizada." }) + + } catch (error: any) { + res.statusCode = 400 + let message = error.sqlMessage || error.message + res.send({ message }) + } + } + + rankingRun = async (req: Request, res: Response) => { + const { competition } = req.body + + try { + const ranking = await this.runnerCompetitionBusiness.getRanking(competition) + res.send({ message: "Resultado da competição", ranking }) + + } catch (error: any) { + res.statusCode = 400 + let message = error.sqlMessage || error.message + res.send({ message }) + } + } + +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Data/BaseDatabase.ts b/modulo5/case-estante-coe/src/Data/BaseDatabase.ts new file mode 100644 index 0000000..1d5f6bb --- /dev/null +++ b/modulo5/case-estante-coe/src/Data/BaseDatabase.ts @@ -0,0 +1,21 @@ +import knex from 'knex' +import dotenv from 'dotenv' + +dotenv.config() + +export abstract class BaseDatabase{ + protected static 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 + } + }) + public static async destroyConnection(): Promise { + await BaseDatabase.connection.destroy(); + } +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Data/DartCompetitionDatabase.ts b/modulo5/case-estante-coe/src/Data/DartCompetitionDatabase.ts new file mode 100644 index 0000000..373dc3f --- /dev/null +++ b/modulo5/case-estante-coe/src/Data/DartCompetitionDatabase.ts @@ -0,0 +1,111 @@ +import { DartCompetitionRepository } from '../Business/DartCompetition/DartCompetitionRepository'; +import { Competition, Progretion } from "../Model/Competition"; +import { BaseDatabase } from "./BaseDatabase"; + +export class DartCompetitionDatabase extends BaseDatabase implements DartCompetitionRepository { + + protected TABLE_NAME = "Dart_CoeCase" + + insert = async (competition: Competition) => { + try { + await BaseDatabase + .connection(this.TABLE_NAME) + .insert(competition) + + return competition + } catch (error: any) { + throw new Error("Erro ao criar atleta no banco de dados. Verifique se o atleta ja está inscrito ") + } + } + + getByAthlete = async (athlete: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT * FROM Dart_CoeCase WHERE athlete = '${athlete}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("Atleta não encontrado") + } + } + + getCompetitionByName = async (competition: string) => { + try { + const result = await BaseDatabase + .connection(this.TABLE_NAME) + .select() + .where("competition", competition) + + return result[0] + } catch (error: any) { + throw new Error("Competição não encontrado.") + } + } + + getCompetitionAndAthlete = async (competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT athlete FROM FROM ${this.TABLE_NAME} WHERE competition = '${competition}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("Erro ao buscar athlete por competição.") + } + } + + + getSituationByName = async (competition: string, situation: Progretion.FINISH) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT Progretion FROM ${this.TABLE_NAME} WHERE competition = '${competition}' and Progretion = '${situation}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("'progress' não encontrado.") + } + } + + updateSituation = async (situation: Progretion.FINISH, competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + UPDATE ${this.TABLE_NAME} SET Progretion = '${situation}' WHERE competition = '${competition}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("Erro ao atualizar competição. Verifique o nome e o progresso da competição.") + } + } + + getRanking = async (competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT competition, athlete, MAX(valor), unity FROM ${this.TABLE_NAME} + WHERE competition = '${competition}' + AND unity = "m" + GROUP BY athlete + ORDER BY MAX(valor) DESC; + `) + + return result[0] + } catch (error: any) { + throw new Error("Erro ao buscar ranking da competição no banco de dados.") + } + } + + getAthleteCount = async (athlete: string, competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT COUNT(athlete) as count FROM ${this.TABLE_NAME} WHERE athlete = '${athlete}' AND competition = '${competition}'; + `) + + return result[0][0].count + } catch (error: any) { + throw new Error("Erro ao buscar count do athlete no banco de dados.") + } + } + +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Data/RunnerDatabase.ts b/modulo5/case-estante-coe/src/Data/RunnerDatabase.ts new file mode 100644 index 0000000..65b9df9 --- /dev/null +++ b/modulo5/case-estante-coe/src/Data/RunnerDatabase.ts @@ -0,0 +1,108 @@ +import { Competition, Progretion } from "../Model/Competition"; +import { BaseDatabase } from "./BaseDatabase"; +import { RunnerCompetitionRepository } from '../Business/RunnerCompetition/RunnerCompetitionRepository'; + +export class RunnerDatabase extends BaseDatabase implements RunnerCompetitionRepository { + + protected TABLE_NAME = "Runner_CoeCase" + + insert = async (competition: Competition) => { + try { + + await BaseDatabase + .connection(this.TABLE_NAME) + .insert(competition) + + return competition + } catch (error: any) { + throw new Error("Erro ao criar atleta no banco de dados. Verifique se o atleta ja está inscrito ") + } + } + getByAthlete = async (athlete: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT * FROM Runner_CoeCase WHERE athlete = '${athlete}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("Atleta não encontrado") + } + } + + getCompetitionByName = async (competition: string) => { + try { + const result = await BaseDatabase + .connection(this.TABLE_NAME) + .select() + .where("competition", competition) + + return result[0] + } catch (error: any) { + throw new Error("Competição não encontrado.") + } + } + + getCompetitionAndAthlete = async (competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT athlete FROM ${this.TABLE_NAME} WHERE competition = '${competition}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("Erro ao buscar athlete por competição.") + } + } + + + getSituationByName = async (competition: string, progretion: Progretion.FINISH) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT Progretion FROM ${this.TABLE_NAME} WHERE competition = '${competition}' and Progretion = '${progretion}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("'progress' não encontrado.") + } + } + + updateSituation = async (situation: Progretion.FINISH, competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + UPDATE ${this.TABLE_NAME} SET Progretion = '${situation}' WHERE competition = '${competition}'; + `) + + return result[0] + } catch (error: any) { + throw new Error("Erro ao atualizar competição. Verifique o nome e o progresso da competição.") + } + } + + getRanking = async (competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT * FROM ${this.TABLE_NAME} WHERE competition = '${competition}' ORDER BY valor ASC; + `) + + return result[0] + } catch (error: any) { + throw new Error("Erro ao buscar ranking da competição no banco de dados.") + } + } + + getAthleteCount = async (athlete: string, competition: string) => { + try { + const result = await BaseDatabase.connection.raw(` + SELECT COUNT(athlete) as count FROM ${this.TABLE_NAME} WHERE athlete = '${athlete}' AND competition = '${competition}'; + `) + + return result[0][0].count + } catch (error: any) { + throw new Error("Erro ao buscar count do atleta no banco de dados.") + } + } + + +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Model/Competition.ts b/modulo5/case-estante-coe/src/Model/Competition.ts new file mode 100644 index 0000000..cb09d8b --- /dev/null +++ b/modulo5/case-estante-coe/src/Model/Competition.ts @@ -0,0 +1,59 @@ +export class Competition { + + constructor( + private id: string, + private competition: string, + private athlete: string, + private valor: string, + private unity: "s" | "m", + private progretion: Progretion + + ) { } + + public getId() { + return this.id + } + + public getCompetition() { + return this.competition + } + + public getAthlete() { + return this.athlete + } + + public getValue() { + return this.valor + } + + public getUnity() { + return this.unity + } + + public getProgretion() { + return this.progretion + } + + static toCompetitionModel(data: any): Competition { + return new Competition(data.id, data.competition, data.athlete, data.valor, data.unity, data.progretion) + } + +} + +export type InputDTO = { + competition: string; + athlete: string; + valor: string; + unity: string; +} + +export enum Progretion { + PROGRESS = "IN PROGRESS", + FINISH = "FINISH" +} + +export type InputcompetitionDTO = { + competition: string +} + + diff --git a/modulo5/case-estante-coe/src/Routes/dartRouter.ts b/modulo5/case-estante-coe/src/Routes/dartRouter.ts new file mode 100644 index 0000000..847082a --- /dev/null +++ b/modulo5/case-estante-coe/src/Routes/dartRouter.ts @@ -0,0 +1,9 @@ +import express from "express"; +import DartCompetitionController from "../Controller/DartCompetitionController"; + +export const dartRouter = express.Router(); +const dartController = new DartCompetitionController(); + +dartRouter.post("/create", dartController.createDart) +dartRouter.post("/finish", dartController.finishDart) +dartRouter.get("/ranking", dartController.rankingDart) \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Routes/runnerRouter.ts b/modulo5/case-estante-coe/src/Routes/runnerRouter.ts new file mode 100644 index 0000000..c4f2e7d --- /dev/null +++ b/modulo5/case-estante-coe/src/Routes/runnerRouter.ts @@ -0,0 +1,9 @@ +import express from "express"; +import { RunnerCompetitionController } from "../Controller/RunnerController"; + +export const runnerRouter = express.Router(); +const runnerController = new RunnerCompetitionController(); + +runnerRouter.post("/create", runnerController.createRunner) +runnerRouter.post("/finish", runnerController.finishRun) +runnerRouter.get("/ranking", runnerController.rankingRun) \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Services/Authenticator.ts b/modulo5/case-estante-coe/src/Services/Authenticator.ts new file mode 100644 index 0000000..4a859a0 --- /dev/null +++ b/modulo5/case-estante-coe/src/Services/Authenticator.ts @@ -0,0 +1,32 @@ +import * as jwt from "jsonwebtoken"; + +export class Authenticator { + public generateToken(input: AuthenticationData, + expiresIn: string = process.env.ACCESS_TOKEN_EXPIRES_IN!): string { + const token = jwt.sign( + { + id: input.id, + role: input.role + }, + process.env.JWT_KEY as string, + { + expiresIn, + } + ); + return token; + } + + public getData(token: string): AuthenticationData { + const payload = jwt.verify(token, process.env.JWT_KEY as string) as any; + const result = { + id: payload.id, + role: payload.role + }; + return result; + } +} + +export interface AuthenticationData { + id: string; + role?: string; +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Services/HashManager.ts b/modulo5/case-estante-coe/src/Services/HashManager.ts new file mode 100644 index 0000000..45704fb --- /dev/null +++ b/modulo5/case-estante-coe/src/Services/HashManager.ts @@ -0,0 +1,17 @@ +import * as bcrypt from "bcryptjs"; + + +export class HashManager { + + public async hash(text: string): Promise { + const rounds = 12; + const salt = await bcrypt.genSalt(rounds); + const result = await bcrypt.hash(text, salt); + return result; + } + + public async compare(text: string, hash: string): Promise{ + return await bcrypt.compare(text, hash); + } + +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Services/IdGeneretor.ts b/modulo5/case-estante-coe/src/Services/IdGeneretor.ts new file mode 100644 index 0000000..3392265 --- /dev/null +++ b/modulo5/case-estante-coe/src/Services/IdGeneretor.ts @@ -0,0 +1,7 @@ +import { v4 } from "uuid"; + +export class IdGenerator{ + public generate(): string{ + return v4() + } +} \ No newline at end of file diff --git a/modulo5/case-estante-coe/src/Services/TokenGenerator.ts b/modulo5/case-estante-coe/src/Services/TokenGenerator.ts new file mode 100644 index 0000000..1e212ba --- /dev/null +++ b/modulo5/case-estante-coe/src/Services/TokenGenerator.ts @@ -0,0 +1,34 @@ +import * as jwt from "jsonwebtoken"; +import dotenv from "dotenv"; + +dotenv.config(); + +export class TokenGenerator { + private static expiresIn: number = 1200; + + public generate = (input: AuthenticationData): string => { + const newToken = jwt.sign( + { + id: input.id, + role: input.role, + }, + process.env.JWT_KEY as string, + { + expiresIn: TokenGenerator.expiresIn, + } + ); + return newToken; + }; + + public verify(token: string) { + const payload = jwt.verify(token, process.env.JWT_KEY as string) as any; + const result = { id: payload.id, role: payload.role }; + return result; + } +} + +export interface AuthenticationData { + id: string; + role: string; +} + diff --git a/modulo5/case-estante-coe/src/index.ts b/modulo5/case-estante-coe/src/index.ts new file mode 100644 index 0000000..4e35d9b --- /dev/null +++ b/modulo5/case-estante-coe/src/index.ts @@ -0,0 +1,22 @@ +import dotenv from "dotenv"; +import { AddressInfo } from "net"; +import express from "express"; +import { runnerRouter } from "./Routes/runnerRouter"; +import { dartRouter } from "./Routes/dartRouter"; + +dotenv.config(); +const app = express(); + +app.use(express.json()); + +app.use("/runner", runnerRouter); +app.use("/dart", dartRouter); + +const server = app.listen(3003, () => { + if (server) { + const address = server.address() as AddressInfo; + console.log(`Servidor rodando em http://localhost:${address.port}`); + } else { + console.error(`Falha ao rodar o servidor.`); + } +}); \ No newline at end of file diff --git a/modulo5/case-estante-coe/tsconfig.json b/modulo5/case-estante-coe/tsconfig.json new file mode 100644 index 0000000..73a1d3d --- /dev/null +++ b/modulo5/case-estante-coe/tsconfig.json @@ -0,0 +1,101 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./build", /* Specify an output folder for all emitted files. */ + "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } + } \ No newline at end of file From 0a4b06af591b2d2efbffe50bf9b13df355ff93e5 Mon Sep 17 00:00:00 2001 From: Vsux Date: Thu, 19 May 2022 17:32:48 -0200 Subject: [PATCH 4/6] cors instalado --- modulo5/case-estante-coe/package.json | 1 + modulo5/case-estante-coe/src/index.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/modulo5/case-estante-coe/package.json b/modulo5/case-estante-coe/package.json index 52b11ef..447b9db 100644 --- a/modulo5/case-estante-coe/package.json +++ b/modulo5/case-estante-coe/package.json @@ -14,6 +14,7 @@ "license": "ISC", "dependencies": { "bcryptjs": "^2.4.3", + "cors": "^2.8.5", "dotenv": "^16.0.1", "jsonwebtoken": "^8.5.1", "typescript": "^4.6.4" diff --git a/modulo5/case-estante-coe/src/index.ts b/modulo5/case-estante-coe/src/index.ts index 4e35d9b..ed80c31 100644 --- a/modulo5/case-estante-coe/src/index.ts +++ b/modulo5/case-estante-coe/src/index.ts @@ -3,11 +3,13 @@ import { AddressInfo } from "net"; import express from "express"; import { runnerRouter } from "./Routes/runnerRouter"; import { dartRouter } from "./Routes/dartRouter"; +import cors from "cors" dotenv.config(); const app = express(); app.use(express.json()); +app.use(cors()) app.use("/runner", runnerRouter); app.use("/dart", dartRouter); From f44eb67844263ac24e20e277805bd12387c4ca44 Mon Sep 17 00:00:00 2001 From: Vsux Date: Fri, 20 May 2022 11:30:37 -0200 Subject: [PATCH 5/6] readme --- modulo5/case-estante-coe/README.md | 41 +++++++++++++++++++ modulo5/case-estante-coe/src/tables/tablessql | 18 ++++++++ 2 files changed, 59 insertions(+) create mode 100644 modulo5/case-estante-coe/src/tables/tablessql diff --git a/modulo5/case-estante-coe/README.md b/modulo5/case-estante-coe/README.md index e69de29..8019076 100644 --- a/modulo5/case-estante-coe/README.md +++ b/modulo5/case-estante-coe/README.md @@ -0,0 +1,41 @@ +# Labenu Music Awards + +### Documentação postman: https://documenter.getpostman.com/view/19296396/UyxhonZD + +### Descrição: + +*Labenu Musical Awards*, um festival com várias bandas famosas para a formatura da turma e, no final, pode eleger a banda que mais gostaram! Permite o gerenciamento completo desses shows. +Utilizamos o LiveShare no VsCode para fazer todo o projeto. +
Para verifica-lo deve-se baixar o arquivo atraves do git clone e instalar as dependencias atraves do npm i + +### Funcionalidades: + +1. Cadastro +2. Login +3. Endpoint de registrar banda +4. Endpoint de visualização de detalhes sobre a banda +5. Endpoint de adicionar um show a um dia +6. Endpoint de pegar todos os shows de uma data + +## 🤝 Colaboradores + + + + + + +
+ + Foto da Grazielle
+ + Grazielle Martins + +
+
+ + foto victor github
+ + Victor Xavier + +
+
diff --git a/modulo5/case-estante-coe/src/tables/tablessql b/modulo5/case-estante-coe/src/tables/tablessql new file mode 100644 index 0000000..6904084 --- /dev/null +++ b/modulo5/case-estante-coe/src/tables/tablessql @@ -0,0 +1,18 @@ + Runner_CoeCase ( + id VARCHAR(255) PRIMARY KEY, + competition VARCHAR(255) , + athlete VARCHAR(255) UNIQUE NOT NULL, + valor VARCHAR(255) NOT NULL, + unity VARCHAR(255) NOT NULL , + Progretion VARCHAR(255) NOT NULL + ); + + + Dart_CoeCase ( + id VARCHAR(255) PRIMARY KEY, + competition VARCHAR(255) , + athlete VARCHAR(255) UNIQUE NOT NULL, + valor VARCHAR(255) NOT NULL, + unity VARCHAR(255) NOT NULL , + Progretion VARCHAR(255) NOT NULL + ); \ No newline at end of file From 0769b08db54178cee6187839429657a98801eb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Victor=20Sim=C3=B5es?= <94612208+Vsux17@users.noreply.github.com> Date: Fri, 20 May 2022 11:35:56 -0200 Subject: [PATCH 6/6] Update README.md --- modulo5/case-estante-coe/README.md | 32 +++++++----------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/modulo5/case-estante-coe/README.md b/modulo5/case-estante-coe/README.md index 8019076..01fc0b7 100644 --- a/modulo5/case-estante-coe/README.md +++ b/modulo5/case-estante-coe/README.md @@ -1,11 +1,14 @@ -# Labenu Music Awards +# Teste prático da EstanteVirtual -### Documentação postman: https://documenter.getpostman.com/view/19296396/UyxhonZD +### Documentação postman: ### Descrição: -*Labenu Musical Awards*, um festival com várias bandas famosas para a formatura da turma e, no final, pode eleger a banda que mais gostaram! Permite o gerenciamento completo desses shows. -Utilizamos o LiveShare no VsCode para fazer todo o projeto. +* Teste prático da EstanteVirtual*, Com a chegada dos jogos olímpicos, fomos designados para construir uma API REST em Ruby para o COB (Comitê Olímico Brasileiro), que será responsável por marcar e dizer os vencedores das seguintes modalidades: +
+As modalidades escolhidas foram: +
100m rasos: Menor tempo vence +
Lançamento de Dardo: Maior distância vence
Para verifica-lo deve-se baixar o arquivo atraves do git clone e instalar as dependencias atraves do npm i ### Funcionalidades: @@ -17,25 +20,4 @@ Utilizamos o LiveShare no VsCode para fazer todo o projeto. 5. Endpoint de adicionar um show a um dia 6. Endpoint de pegar todos os shows de uma data -## 🤝 Colaboradores - - - - - -
- - Foto da Grazielle
- - Grazielle Martins - -
-
- - foto victor github
- - Victor Xavier - -
-