diff --git a/Md03_Dev_Back_end/Bloco22/22.3/README.md b/Md03_Dev_Back_end/Bloco22/22.3/README.md new file mode 100644 index 00000000..e69de29b diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/app.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/app.js index a8bb0cde..353461f5 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/app.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/app.js @@ -1,12 +1,10 @@ const express = require('express'); -const connection = require('./models/connection'); -const { travelModel } = require('./models'); -const { passagerRoute, driverRoute } = require('./routes'); +const { passengerRoute, driverRoute } = require('./routes'); const app = express(); app.use(express.json()); -app.use('/passengers', passagerRoute); +app.use('/passengers', passengerRoute); app.use('/drivers', driverRoute); module.exports = app; diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/controllers/passenger.controller.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/controllers/passenger.controller.js new file mode 100644 index 00000000..426656df --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/controllers/passenger.controller.js @@ -0,0 +1,22 @@ +// src/controllers/passenger.controller.js +const passengerService = require('../services/passenger.service'); +const { mapError } = require('../utils/errorMap'); + +const createTravel = async (req, res) => { + const { passengerId } = req.params; + const { startingAddress, endingAddress, waypoints } = req.body; + + const { type, message } = await passengerService.requestTravel(passengerId, startingAddress, endingAddress, waypoints); + + // Linha de código responsável por gerar uma resposta em caso de erro no + // processamento do componente de software da camada `Service` + if (type) { + return res.status(mapError(type)).json(message); + } + + res.status(201).json(message); +}; + +module.exports = { + createTravel, +}; diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/models/driver.model.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/models/driver.model.js index 956ed713..da124ae0 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/models/driver.model.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/models/driver.model.js @@ -8,6 +8,15 @@ const findAll = async () => { return camelize(result); } +const findById = async (driverId) => { + const [[result]] = await connection.execute( + 'SELECT * FROM drivers WHERE id = ?', + [driverId], + ); + return camelize(result); +}; + module.exports = { findAll, + findById } \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/models/index.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/models/index.js index 652da4a3..eed730e8 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/models/index.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/models/index.js @@ -1,11 +1,11 @@ const travelModel = require('./travel.model'); const driverModel = require('./driver.model'); -const passagerModel = require('./passager.model'); +const passengerModel = require('./passenger.model'); const waypointModel = require('./waypoint.model'); module.exports = { travelModel, driverModel, - passagerModel, + passengerModel, waypointModel, } \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/models/passager.model.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/models/passenger.model.js similarity index 100% rename from Md03_Dev_Back_end/Bloco22/exercicios/src/models/passager.model.js rename to Md03_Dev_Back_end/Bloco22/exercicios/src/models/passenger.model.js diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/driver.router.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/driver.router.js new file mode 100644 index 00000000..25101001 --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/driver.router.js @@ -0,0 +1,47 @@ +const { Router } = require('express'); +const { driverService } = require('../services'); +const { mapError } = require('../utils/errorMap'); + +const route = Router(); + +route.get('/open/travels', async (_req, res) => { + const { type, message } = await driverService.getWaitingDriverTravels(); + + if (type) return res.status(mapError(type)).json({ message }); + + res.status(200).json(message); +}); + +route.get('/', async (_req,res) => { + const { type, message } = await driverService.findAll(); + + if (type) return res.status(mapError(type)).json({ message }); + + res.status(200).json(message); +}); + +route.put('/:driverId/travels/:travelId/assign', async (req, res) => { + const { type, message } = await driverService.travelAssign(req.params); + + if (type) return res.status(mapError(type)).json({ message }); + + res.status(200).json(message); +}); + +route.put('/:driverId/travels/:travelId/start', async (req, res) => { + const { type, message } = await driverService.startTravel(req.params); + + if (type) return res.status(mapError(type)).json({ message }); + + res.status(200).json(message); +}); + +route.put('/:driverId/travels/:travelId/end', async (req, res) => { + const { type, message } = await driverService.endTravel(req.params); + + if (type) return res.status(mapError(type)).json({ message }); + + res.status(200).json(message); +}); + +module.exports = route; \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/driverRoute.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/driverRoute.js deleted file mode 100644 index 05776db0..00000000 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/driverRoute.js +++ /dev/null @@ -1,49 +0,0 @@ -const { Router } = require('express'); -const { driverModel, travelModel } = require('../models'); -const connection = require('../models/connection'); - -const route = Router(); - -const WAITING_DRIVER = 1; -const DRIVER_ON_THE_WAY = 2; -const TRAVEL_IN_PROGRESS = 3; -const TRAVEL_FINISHED = 4; - -route.get('/open/travels', async (_req, res) => { - const result = await travelModel.findByTravelStatusId(WAITING_DRIVER); - - res.status(200).json(result); -}); - -route.get('/', async (_req,res) => { - const result = await driverModel.findAll(); - - res.status(200).json(result); -}); - -route.put('/:driverId/travels/:travelId/assign', async (req, res) => { - const { travelId, driverId } = req.params; - - await travelModel.setDriver(travelId, driverId); - await travelModel.setStatus(DRIVER_ON_THE_WAY, travelId, driverId); - const result = await travelModel.findById(travelId); - res.status(200).json(result); -}); - -route.put('/:driverId/travels/:travelId/start', async (req, res) => { - const { travelId, driverId } = req.params; - - await travelModel.setStatus(TRAVEL_IN_PROGRESS, travelId, driverId); - const result = await travelModel.findById(travelId); - res.status(200).json(result); -}); - -route.put('/:driverId/travels/:travelId/end', async (req, res) => { - const { travelId, driverId } = req.params; - - await travelModel.setStatus(TRAVEL_FINISHED, travelId, driverId); - const result = await travelModel.findById(travelId); - res.status(200).json(result); -}); - -module.exports = route; \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/index.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/index.js index 9459593c..c7dde2f9 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/index.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/index.js @@ -1,7 +1,7 @@ -const driverRoute = require("./driverRoute"); -const passagerRoute = require("./passagerRoute"); +const driverRoute = require("./driver.router"); +const passengerRoute = require("./passenger.router.js"); module.exports = { driverRoute, - passagerRoute, + passengerRoute, } \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/passagerRoute.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/passagerRoute.js deleted file mode 100644 index 458b2045..00000000 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/passagerRoute.js +++ /dev/null @@ -1,17 +0,0 @@ -const { Router } = require('express'); -const { requestTravel } = require('../services/passager.service'); - -const route = Router(); - -route.post('/:passengerId/request/travel', async (req, res) => { - const { passengerId } = req.params; - const { startingAddress, endingAddress, waypoints } = req.body; - - const result = await requestTravel(passengerId, startingAddress, endingAddress, waypoints); - - if (!result.type) return res.status(201).json(result.message); - - res.status(500).json({ message: result.message }); -}); - -module.exports = route; \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/passenger.router.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/passenger.router.js new file mode 100644 index 00000000..6d9b5f42 --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/routes/passenger.router.js @@ -0,0 +1,8 @@ +const { Router } = require('express'); +const { createTravel } = require('../controllers/passenger.controller'); + +const route = Router(); + +route.post('/:passengerId/request/travel', createTravel); + +module.exports = route; \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/driver.service.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/driver.service.js new file mode 100644 index 00000000..e7d3477c --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/driver.service.js @@ -0,0 +1,69 @@ +const { travelModel, driverModel } = require('../models'); +const { + validateInputValues, + validateAlreadyDriver, +} = require('./validations/validationsInputValues'); + +const WAITING_DRIVER = 1; +const DRIVER_ON_THE_WAY = 2; +const TRAVEL_IN_PROGRESS = 3; +const TRAVEL_FINISHED = 4; + +const getWaitingDriverTravels = async () => { + const result = await travelModel.findByTravelStatusId(WAITING_DRIVER); + + if (result.length > 0) return { type: null, message: result }; + + return { type: 'TRAVEL_NOT_FOUND', message: 'Not found waiting travel' }; +} + +const findAll = async () => { + const result = await driverModel.findAll(); + + if (result.length > 0) return { type: null, message: result }; + + return { type: 'DRIVER_NOT_FOUND', message: 'Not found driver' }; +} + +async function setStatus(status, travelId, driverId) { + await travelModel.setStatus(status, travelId, driverId); + + const result = await travelModel.findById(travelId); + return { type: null, message: result }; +} + +const travelAssign = async ({ travelId, driverId }) => { + let error = await checkValidations({ travelId, driverId }); + + if (error.type) return error; + + error = await validateAlreadyDriver(travelId); + if (error.type) return error; + + await travelModel.setDriver(travelId, driverId); + return await setStatus(DRIVER_ON_THE_WAY, travelId, driverId); +} + +const startTravel = async ({ travelId, driverId }) => { + const error = await validateInputValues({ travelId, driverId }); + + if (error.type) return error; + + return await setStatus(TRAVEL_IN_PROGRESS, travelId, driverId); +} + +const endTravel = async ({ travelId, driverId }) => { + const error = await validateInputValues({ travelId, driverId }); + + if (error.type) return error; + + return await setStatus(TRAVEL_FINISHED, travelId, driverId); +} + +module.exports = { + getWaitingDriverTravels, + findAll, + travelAssign, + startTravel, + endTravel +}; diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/index.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/index.js new file mode 100644 index 00000000..5f8384b8 --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/index.js @@ -0,0 +1,7 @@ +const passengerService = require('./passenger.service'); +const driverService = require('./driver.service'); + +module.exports = { + passengerService, + driverService +} \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/passager.service.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/passenger.service.js similarity index 88% rename from Md03_Dev_Back_end/Bloco22/exercicios/src/services/passager.service.js rename to Md03_Dev_Back_end/Bloco22/exercicios/src/services/passenger.service.js index da89b61e..e8fbcabd 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/passager.service.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/passenger.service.js @@ -1,8 +1,8 @@ -const { travelModel, passagerModel, waypointModel } = require('../models'); +const { travelModel, passengerModel, waypointModel } = require('../models'); const { validateRequestTravelSchema } = require('./validations/validationsInputValues'); const doesPassengerExist = async (passengerId) => { - const passenger = await passagerModel.findById(passengerId); + const passenger = await passengerModel.findById(passengerId); if (passenger) return true; return false; diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/schemas.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/schemas.js index b3e88c90..e3868860 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/schemas.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/schemas.js @@ -15,7 +15,14 @@ const addRequestTravelSchema = Joi.object({ waypoints: Joi.array().items(waypointSchema) }); +const addPassengerSchema = Joi.object({ + name: Joi.string().min(3).required(), + email: Joi.string().email().required(), + phone: Joi.string().min(9).max(20).required() +}); + module.exports = { idSchema, addRequestTravelSchema, + addPassengerSchema, }; \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/validationsInputValues.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/validationsInputValues.js index e7d0ce72..9898ba7a 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/validationsInputValues.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/services/validations/validationsInputValues.js @@ -1,5 +1,6 @@ // src/services/validations/validationsInputValues.js -const { addRequestTravelSchema } = require('./schemas'); +const { travelModel, driverModel } = require('../../models'); +const { addRequestTravelSchema, idSchema, addPassengerSchema } = require('./schemas'); const validateRequestTravelSchema = (passengerId, startingAddress, endingAddress, waypoints) => { const { error } = addRequestTravelSchema @@ -9,6 +10,47 @@ const validateRequestTravelSchema = (passengerId, startingAddress, endingAddress return { type: null, message: '' }; }; +const validateInputValues = async ({ travelId, driverId }) => { + /* Valida se travelId existe */ + const travel = await travelModel.findById(travelId); + if (!travel) return { type: 'TRAVEL_NOT_FOUND', message: 'travel id not found' }; + + /* Valida se driverId existe */ + const driver = await driverModel.findById(driverId); + if (!driver) return { type: 'DRIVER_NOT_FOUND', message: 'driver id not found' }; + + return { type: null, message: '' }; +}; + +const validateAlreadyDriver = async (travelId) => { + const travel = await travelModel.findById(travelId); + + if (travel && travel.driverId) { + return { type: 'TRAVEL_CONFLICT', message: 'travel already assigned' }; + } + + return { type: null, message: '' }; +}; + +const validateId = (id) => { + const { error } = idSchema.validate(id); + if (error) return { type: 'INVALID_VALUE', message: '"id" must be a number' }; + + return { type: null, message: '' }; +}; + +const validateNewPassenger = (name, email, phone) => { + const { error } = addPassengerSchema + .validate({ name, email, phone }); + if (error) return { type: 'INVALID_VALUE', message: error.message }; + + return { type: null, message: '' }; +}; + module.exports = { validateRequestTravelSchema, + validateInputValues, + validateAlreadyDriver, + validateId, + validateNewPassenger }; \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/src/utils/errorMap.js b/Md03_Dev_Back_end/Bloco22/exercicios/src/utils/errorMap.js new file mode 100644 index 00000000..a9d59ecf --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/src/utils/errorMap.js @@ -0,0 +1,13 @@ +const errorMap = { + TRAVEL_NOT_FOUND: 404, + DRIVER_NOT_FOUND: 404, + INVALID_VALUE: 422, + TRAVEL_CONFLICT: 409, +}; + +const mapError = (type) => errorMap[type] || 500; + +module.exports = { + errorMap, + mapError, +}; \ No newline at end of file diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/controllers/mocks/passenger.controller.mock.js b/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/controllers/mocks/passenger.controller.mock.js new file mode 100644 index 00000000..6a8e8971 --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/controllers/mocks/passenger.controller.mock.js @@ -0,0 +1,49 @@ +// tests/unit/controllers/mocks/passenger.controller.mock.js +const happyReqCreateTravelObject = { + params: { + passengerId: 42, + }, + body: { + startingAddress: 'Rua X', + endingAddress: 'Rua Y', + waypoints: [ + { + address: 'Ponto 01', + stopOrder: '1', + }, + { + address: 'Ponto 02', + stopOrder: '2', + }, + ], + }, +}; + +const happyControllerResponseCreateTravelObject = { + type: null, + message: { + id: 3, + passengerId: 3, + driverId: null, + travelStatusId: 1, + startingAddress: 'Rua X', + endingAddress: 'Rua Y', + requestDate: '2022-08-28T21:10:35.000Z', + }, +}; + +const happyResponseCreateTravelObject = { + id: 3, + passengerId: 3, + driverId: null, + travelStatusId: 1, + startingAddress: 'Rua X', + endingAddress: 'Rua Y', + requestDate: '2022-08-28T21:10:35.000Z', +}; + +module.exports = { + happyReqCreateTravelObject, + happyControllerResponseCreateTravelObject, + happyResponseCreateTravelObject, +}; diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/controllers/passenger.controller.test.js b/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/controllers/passenger.controller.test.js new file mode 100644 index 00000000..62ef415e --- /dev/null +++ b/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/controllers/passenger.controller.test.js @@ -0,0 +1,50 @@ +// tests/unit/controllers/passenger.controller.test.js +const chai = require('chai'); +const sinon = require('sinon'); +const sinonChai = require('sinon-chai'); + +const { expect } = chai; +chai.use(sinonChai); + +const passengerService = require('../../../src/services/passenger.service'); +const passengerController = require('../../../src/controllers/passenger.controller'); + +// Aqui estamos importando os dados de mock +const { + happyControllerResponseCreateTravelObject, + happyReqCreateTravelObject, + happyResponseCreateTravelObject, +} = require('./mocks/passenger.controller.mock'); + +describe('Teste de unidade do passengerController', function () { + it('Criando uma nova viagem', async function () { + // Este é o objeto de resposta (res) inicialmente é um objeto vazio + // que será preenchido pelo express + const res = {}; + + // Este é o objeto de requisição (req) que contém os dados necessários + // para a requisição que ocorre sem nenhum problema + const req = happyReqCreateTravelObject; + + // Criamos um stub para a função "res.status" que retorna o objeto res quando executada + res.status = sinon.stub().returns(res); + + // Criamos um stub para a função "res.json" que não retorna nada + res.json = sinon.stub().returns(); + + // Criamos um stub para a chamada do service "passengerService.requestTravel" que irá + // retornar uma resposta sem erros + sinon + .stub(passengerService, 'requestTravel') + .resolves(happyControllerResponseCreateTravelObject); + + // Realizamos a chamada para o controller simulando o recebimento de uma requisição + await passengerController.createTravel(req, res); + + // Validamos se o status code da resposta é igual a 201 + expect(res.status).to.have.been.calledWith(201); + + // Validamos se o json da resposta é igual ao do mock + expect(res.json).to.have.been.calledWith(happyResponseCreateTravelObject); + }); +}); diff --git a/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/services/passenger.service.test.js b/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/services/passenger.service.test.js index 521b7508..7580d5cb 100644 --- a/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/services/passenger.service.test.js +++ b/Md03_Dev_Back_end/Bloco22/exercicios/tests/unit/services/passenger.service.test.js @@ -1,9 +1,9 @@ // tests/unit/services/passenger.service.test.js const { expect } = require('chai'); const sinon = require('sinon'); -const { requestTravel } = require('../../../src/services/passager.service'); +const { requestTravel } = require('../../../src/services/passenger.service'); -const { travelModel, waypointModel, passagerModel } = require('../../../src/models'); +const { travelModel, waypointModel, passengerModel } = require('../../../src/models'); const { travelResponse } = require('./mocks/passenger.service.mock'); @@ -11,7 +11,7 @@ describe('Verificando service pessoa passageira', function () { describe('solicitação de viagem', function () { it('sem pontos de parada é realizada com sucesso', async function () { // arrange - sinon.stub(passagerModel, 'findById').resolves(true); // retorna verdadeiro sinalizando que o passageiro existe + sinon.stub(passengerModel, 'findById').resolves(true); // retorna verdadeiro sinalizando que o passageiro existe sinon.stub(travelModel, 'insert').resolves(1); // retorna travel com ID 1 sinon.stub(travelModel, 'findById').resolves(travelResponse); @@ -41,7 +41,7 @@ describe('Verificando service pessoa passageira', function () { it('com pontos de parada é realizada com sucesso', async function () { // arrange - sinon.stub(passagerModel, 'findById').resolves(true); // retorna verdadeiro sinalizando que o passageiro existe + sinon.stub(passengerModel, 'findById').resolves(true); // retorna verdadeiro sinalizando que o passageiro existe sinon.stub(travelModel, 'insert').resolves(1); // retorna travel com ID 1 sinon.stub(travelModel, 'findById').resolves(travelResponse); sinon.stub(waypointModel, 'insert').resolves(1); // retorna waypoint com ID 1