serverest 2.25.3 → 2.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.26.1](https://github.com/ServeRest/ServeRest/compare/v2.26.0...v2.26.1) (2022-07-08)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * show user that request ended with timeout ([1f432c4](https://github.com/ServeRest/ServeRest/commit/1f432c429647c871b2075dc8a4259ab52e714e04))
9
+
10
+ # [2.26.0](https://github.com/ServeRest/ServeRest/compare/v2.25.4...v2.26.0) (2022-06-19)
11
+
12
+
13
+ ### Chores
14
+
15
+ * avoid action unpublished version ([15fab7f](https://github.com/ServeRest/ServeRest/commit/15fab7f4565ef46350cc8959669e1430f02aec03)), closes [#310](https://github.com/ServeRest/ServeRest/issues/310)
16
+
17
+
18
+ ### Continuous Integration
19
+
20
+ * run mutation test only when files in src/ dir change ([0ed60ad](https://github.com/ServeRest/ServeRest/commit/0ed60ad04bf0db573c7ba23c1ba8826708f29711))
21
+
22
+
23
+ ### Features
24
+
25
+ * allow load test and route /status to get infos ([7098bff](https://github.com/ServeRest/ServeRest/commit/7098bffed401ec001a1d5eef0406a406a6fd6e97))
26
+
27
+ ## [2.25.4](https://github.com/ServeRest/ServeRest/compare/v2.25.3...v2.25.4) (2022-06-19)
28
+
29
+
30
+ ### Chores
31
+
32
+ * **terratest:** remove specific version that prevents docker build ([7e18f99](https://github.com/ServeRest/ServeRest/commit/7e18f994acd306eb31bbd37c9f6efe80a231f440))
33
+
34
+
35
+ ### Code Refactoring
36
+
37
+ * **dockerfile:** split multi-stage docker on 2 files to improve docker build time ([0971a56](https://github.com/ServeRest/ServeRest/commit/0971a56ccb5360770c511374b2fe83e84b6d7096))
38
+
39
+
40
+ ### Continuous Integration
41
+
42
+ * automatic deploy to staging and prod, e2e test and rollback ([10948da](https://github.com/ServeRest/ServeRest/commit/10948dab55428981a425502a7db0f2a02fac4167))
43
+ * cancelar execução anterior em um novo git push ([461eba0](https://github.com/ServeRest/ServeRest/commit/461eba0af5ff5ee43855b396b88e579971e64e95))
44
+ * **e2e:** e2e test must be mandatory for guarantee the release quality ([f239f6d](https://github.com/ServeRest/ServeRest/commit/f239f6d0960b78d564689963161d79bf170238d3))
45
+
46
+
47
+ ### Documentation
48
+
49
+ * **contributing:** info about continous delivery and about validations ([14d12b5](https://github.com/ServeRest/ServeRest/commit/14d12b5a77af1de14148f364fb39e5515e421c7a))
50
+ * **serverest:** allow import collection to postman ([c5e9bc8](https://github.com/ServeRest/ServeRest/commit/c5e9bc8779f4d20a152fed50cac2ebbee99cb149))
51
+ * **serverest:** show correct version on swagger instead 2.x.x ([75cf178](https://github.com/ServeRest/ServeRest/commit/75cf178c884825d9bb5d215261039ad604efb554))
52
+
53
+
54
+ ### Tests
55
+
56
+ * **docs:** validate that documentation is accessible - [#202](https://github.com/ServeRest/ServeRest/issues/202) ([7ba01cf](https://github.com/ServeRest/ServeRest/commit/7ba01cf654e0c7d0e138655d7df1b435246213bb))
57
+ * **e2e:** allow E2E testing of production application ([f8c28cf](https://github.com/ServeRest/ServeRest/commit/f8c28cf54eeaf2e8452a474453e45822fcc5c9c7))
58
+
3
59
  ## [2.25.3](https://github.com/ServeRest/ServeRest/compare/v2.25.2...v2.25.3) (2022-03-18)
4
60
 
5
61
 
package/README.md CHANGED
@@ -25,6 +25,7 @@
25
25
 
26
26
  _ServeRest_ permite o estudo de:
27
27
  - Verbos *GET, POST, PUT* e *DELETE* com persistência de dados
28
+ - [Teste de carga](#teste-de-carga)
28
29
  - Autenticação no header
29
30
  - Query string
30
31
  - Teste de schema json
@@ -52,7 +53,7 @@ Todas essas opções possuem as mesmas rotas, regras, dados pré-cadastrados e d
52
53
 
53
54
  No ambiente online os dados cadastrados são removidos diariamente, enquanto que no local basta reiniciar o ServeRest.
54
55
 
55
- Prefira a opção de ambiente local caso precise que os dados não sejam alterados por outro usuário.
56
+ > Prefira a opção de ambiente local caso precise que os dados não sejam alterados por outro usuário.
56
57
 
57
58
  ### Online
58
59
 
@@ -60,10 +61,7 @@ Acesse **<https://serverest.dev>** para visualizar a documentação e as rotas d
60
61
 
61
62
  > Essa é a melhor opção para quem não possui NPM e Docker na máquina ou não quer preocupar em gerenciar ambiente.
62
63
 
63
- A base de dados volta ao estado original [diariamente às 3h](https://github.com/ServeRest/ServeRest/actions?query=workflow%3A%22Clean+serverest.dev+database%22).
64
-
65
64
  O ServeRest online possui monitoramento constante do status e tempo de atividade para garantir que esteja sempre disponível.
66
- Acesse [ServeRest Status](https://status.serverest.dev/) para ver detalhes do uptime.
67
65
 
68
66
  ### Localmente com NPM
69
67
 
@@ -127,6 +125,28 @@ Em ambos os comandos de subida de ambiente local será utilizado a última vers
127
125
 
128
126
  Você pode encontrar as versões disponíveis na [lista de tags no Docker Hub](https://hub.docker.com/r/paulogoncalvesbh/serverest/tags) e na [lista de versões do NPM](https://www.npmjs.com/package/serverest).
129
127
 
128
+ ## Teste de carga
129
+
130
+ ### IMPORTANTE
131
+
132
+ 1. É obrigatório enviar o header `monitor: false` em todas as requisições do seu teste de carga.
133
+ 2. O teste de carga deve ser executado apenas em ambiente local (disponibilizado via [NPM](#localmente-com-npm) ou [Docker](#localmente-com-docker) e acessível via <http://localhost:3000>).
134
+
135
+ > O não seguimento dos 2 tópicos acimas vai acarretar em prejuízo para o projeto open source e gratuito e irá impactar o estudo de outras pessoas.
136
+
137
+ ### Acesso ao status
138
+
139
+ Para acompanhar o comportamento do ServeRest diante dos seus testes você pode acessar a página <http://localhost:3000/status>, que contém informações como:
140
+
141
+ - Uso de CPU.
142
+ - Uso da memória.
143
+ - Tempo de resposta.
144
+ - RPS (Requisições por segundo).
145
+
146
+ A página de status (_/status_) está disponível apenas localmente.
147
+
148
+ > Fez teste de carga? O que acha de compartilhar com o autor do projeto o repositório e o relatório final contendo dados de RPS para auxiliar o ServeRest a entender o comportamento de sua infra?
149
+
130
150
  ## Badge
131
151
 
132
152
  Criou repositório utilizando o ServeRest? Adicione o código abaixo no topo do README.md para ter a badge do projeto.
@@ -158,7 +178,15 @@ Sua empresa usa o ServeRest? Pergunte ao seu gerente ou equipe de marketing se s
158
178
  1. Subdomínio próprio (_nome-escolhido.serverest.dev_)
159
179
  1. Acesso a todas as requests e respostas feitas nos últimos 7 dias no subdomínio
160
180
 
161
- [![Apoiador individual - Open Collective](https://opencollective.com/serverest/tiers/patrocinador.svg)](https://opencollective.com/serverest)
181
+ [![Empresas - Open Collective](https://opencollective.com/serverest/tiers/patrocinador.svg)](https://opencollective.com/serverest)
182
+
183
+ Empresas que apoiam o ServeRest:
184
+
185
+ <p align="center">
186
+ <img alt="Logo da EBAC" src="https://user-images.githubusercontent.com/29241659/177436481-2a6a3324-1b0e-4d28-8a40-d885f54291c0.png#gh-light-mode-only" height="120">
187
+ <img alt="Logo da EBAC" src="https://user-images.githubusercontent.com/29241659/177436489-5d2f50f8-2fb3-4091-b822-446d24c83722.png#gh-dark-mode-only" height="120">
188
+ <img alt="Logo da Agilizei" src="https://user-images.githubusercontent.com/29241659/177436678-8187f90f-bb4a-4978-87ab-a03f2f80820f.png" height="124">
189
+ </p>
162
190
 
163
191
  ### Individuais
164
192
 
@@ -190,6 +218,8 @@ Veja aqui [como você pode contribuir](https://github.com/ServeRest/ServeRest/bl
190
218
  <td align="center"><a href="https://about.me/rustnnes"><img src="https://avatars1.githubusercontent.com/u/638445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Diego Bandeira</b></sub></a><br /><a href="#infra-rustnnes" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
191
219
  <td align="center"><a href="https://github.com/maximilianoalves"><img src="https://avatars3.githubusercontent.com/u/11561118?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Maximiliano Alves</b></sub></a><br /><a href="#talk-maximilianoalves" title="Talks">📢</a></td>
192
220
  <td align="center"><a href="https://github.com/murilomaiaa"><img src="https://avatars.githubusercontent.com/u/56596799?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Murilo Maia</b></sub></a><br /><a href="https://github.com/ServeRest/ServeRest/commits?author=murilomaiaa" title="Code">💻</a></td>
221
+ <td align="center"><a href="https://github.com/crisnazario"><img src="https://avatars.githubusercontent.com/u/37200398?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cristina Nazário</b></sub></a><br /><a href="#ideas-crisnazario" title="Ideas, Planning, & Feedback">🤔</a></td>
222
+ <td align="center"><a href="http://www.eduardosantos.dev"><img src="https://avatars.githubusercontent.com/u/10568807?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eduardo Santos</b></sub></a><br /><a href="https://github.com/ServeRest/ServeRest/commits?author=edumaxsantos" title="Code">💻</a></td>
193
223
  </tr>
194
224
  </table>
195
225
 
package/docs/swagger.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "swagger": "2.0",
3
3
  "info": {
4
- "description": "**O ServeRest é uma API REST que simula uma loja virtual com intuito de servir de material de estudos de testes de API.**\n\n_**Deixe um star no repositorio: [github.com/ServeRest/ServeRest](https://github.com/ServeRest/ServeRest).**_\n\nEssa página documenta todas as rotas e como acessá-las. Para mais detalhes do ServeRest (como executar localmente utilizando Docker ou NPM, alterar timeout de autenticação, etc) acesse [o repositório do ServeRest](https://github.com/serverest/serverest).\n\n\nMuito obrigado ♥ a todos que apoiam o projeto [financeiramente](https://opencollective.com/serverest#section-contributors) ou [com código, ideias e divulgação](https://github.com/ServeRest/ServeRest#contribuidores-).\n\nO ServeRest possui um front, com status em beta, não deixe de conhecer: [front.serverest.dev](https://front.serverest.dev).\n\nPrecisa de apoio? [Abra uma issue](https://github.com/ServeRest/ServeRest/issues) ou contate o mantenedor do projeto:\n",
4
+ "description": "**O ServeRest é uma API REST gratuita que simula uma loja virtual com intuito de servir de material de estudos de testes de API.**\n\n**Não deixe de seguir o [autor do projeto](https://github.com/PauloGoncalvesBH) e deixar um star no repositório: [github.com/ServeRest/ServeRest](https://github.com/ServeRest/ServeRest)**\n\nEssa página documenta todas as rotas e como acessá-las. Para mais detalhes do ServeRest (como executar localmente utilizando Docker ou NPM, alterar timeout de autenticação, etc) acesse [o repositório do ServeRest](https://github.com/serverest/serverest).\n\nEstá utilizando Postman? Importe o [JSON do Swagger](https://raw.githubusercontent.com/ServeRest/ServeRest/trunk/docs/swagger.json) para ter acesso às collections.\n\nVai fazer teste de carga? Leia a seção '[Teste de Carga](https://github.com/ServeRest/ServeRest#teste-de-carga)'.\n\n\nMuito obrigado ♥ a todos que apoiam o projeto [financeiramente](https://opencollective.com/serverest#section-contributors) ou [com código, ideias e divulgação](https://github.com/ServeRest/ServeRest#contribuidores-), graças a vocês **mais de R$ 2000,00 foram doados para a ONG [Todas as letras](https://todasasletras.org/)** até o momento.\n\nO ServeRest possui um front, com status em beta, não deixe de conhecer: [front.serverest.dev](https://front.serverest.dev).\n\nPrecisa de apoio? [Abra uma issue](https://github.com/ServeRest/ServeRest/issues) ou contate o mantenedor do projeto:\n",
5
5
  "version": "2.X.X",
6
6
  "title": "ServeRest",
7
7
  "contact": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serverest",
3
- "version": "2.25.3",
3
+ "version": "2.26.1",
4
4
  "description": "Servidor REST local de forma rápida e simples para estudo de testes de API",
5
5
  "author": "Paulo Gonçalves <paulorochag@hotmail.com> (https://www.linkedin.com/in/paulo-goncalves/)",
6
6
  "license": "GPL-3.0",
@@ -34,8 +34,10 @@
34
34
  "dev": "nodemon --legacy-watch -e json,js ./src/server.js --nodoc",
35
35
  "test:mutation": "stryker run ./test/stryker.conf.js",
36
36
  "test:mutation:diff": "stryker-diff-runner --path ./test/stryker.conf.js --branch trunk",
37
- "test:unit": "nyc --report-dir ./coverage-unit mocha --config test/unit/.mocharc.js",
37
+ "test:unit": "nyc --report-dir ./coverage-unit --check-coverage false mocha --config test/unit/.mocharc.js",
38
38
  "test:integration": "nyc --report-dir ./coverage-integration mocha --config test/integration/.mocharc.js",
39
+ "test:e2e": "mocha --config test/integration/.mocharc.js --fgrep @skipE2E --invert",
40
+ "test:smoke": "mocha --config test/integration/.mocharc.js --grep @smokeE2E",
39
41
  "merge-lcov": "npx lcov-result-merger@3.1.0 'coverage-**/lcov.info' 'lcov.info'",
40
42
  "lint": "standard",
41
43
  "lint:fix": "standard --fix",
@@ -50,6 +52,7 @@
50
52
  "express": "^4.17.1",
51
53
  "express-async-errors": "^3.1.1",
52
54
  "express-query-int": "^3.0.0",
55
+ "express-status-monitor": "1.3.4",
53
56
  "express-validation": "^3.0.8",
54
57
  "is-ci": "^3.0.0",
55
58
  "jsonwebtoken": "^8.5.1",
package/src/app.js CHANGED
@@ -10,13 +10,14 @@ const timeout = require('connect-timeout')
10
10
  const { join } = require('path')
11
11
  const swaggerUi = require('swagger-ui-express')
12
12
 
13
- const { formaDeExecucao, urlDocumentacao } = require('./utils/ambiente')
13
+ const { aplicacaoExecutandoLocalmente, formaDeExecucao, urlDocumentacao } = require('./utils/ambiente')
14
14
  const { conf } = require('./utils/conf')
15
15
  const errorHandler = require('./middlewares/error-handler')
16
16
  const logger = require('./utils/logger')
17
17
  const { version } = require('../package.json')
18
18
  const swaggerDocument = require('../docs/swagger.json')
19
19
  const rateLimiter = require('./middlewares/rate-limiter')
20
+ const packageJson = require('../package.json')
20
21
 
21
22
  const ehAmbienteDeTestes = process.env.NODE_ENV === 'serverest-test'
22
23
 
@@ -46,6 +47,11 @@ if (!conf.semHeaderDeSeguranca) {
46
47
  })
47
48
  }
48
49
 
50
+ /* istanbul ignore next */
51
+ if (aplicacaoExecutandoLocalmente() && !ehAmbienteDeTestes) {
52
+ app.use(require('express-status-monitor')({ title: 'ServeRest Status' }))
53
+ }
54
+
49
55
  logger(app)
50
56
 
51
57
  /* istanbul ignore next */
@@ -53,11 +59,16 @@ switch (formaDeExecucao()) {
53
59
  case 'serverest.dev':
54
60
  swaggerDocument.host = 'serverest.dev'
55
61
  break
62
+ case 'staging.serverest.dev':
63
+ swaggerDocument.host = 'staging.serverest.dev'
64
+ break
56
65
  case 'agilizei':
57
66
  swaggerDocument.host = 'agilizei.serverest.dev'
58
67
  break
59
68
  }
60
69
 
70
+ swaggerDocument.info.version = packageJson.version
71
+
61
72
  const uiOptions = {
62
73
  customSiteTitle: 'ServeRest',
63
74
  customfavIcon: '/favicon.ico',
@@ -1,10 +1,8 @@
1
1
  'use strict'
2
2
 
3
- const authService = require('../services/auth-service')
4
3
  const constant = require('../utils/constants')
5
4
  const produtosService = require('../services/produtos-service')
6
5
  const service = require('../services/carrinhos-service')
7
- const usuariosService = require('../services/usuarios-service')
8
6
 
9
7
  exports.get = async (req, res) => {
10
8
  const carrinhos = await service.getAll(req.query)
@@ -21,53 +19,40 @@ exports.getOne = async (req, res) => {
21
19
  }
22
20
 
23
21
  exports.post = async (req, res) => {
24
- const { email, password } = authService.verifyToken(req.headers.authorization)
25
- const { _id } = await usuariosService.getDadosDoUsuario({ email, password })
26
- const usuarioJaPossuiCarrinho = await service.existeCarrinho({ idUsuario: _id })
27
- if (usuarioJaPossuiCarrinho) {
22
+ const { idUsuario, possuiCarrinho } = await service.usuarioJaPossuiCarrinho(req.headers.authorization)
23
+ if (possuiCarrinho) {
28
24
  return res.status(400).send({ message: constant.LIMITE_1_CARRINHO })
29
25
  }
30
26
 
31
27
  const idProdutosDuplicados = service.extrairProdutosDuplicados(req.body.produtos)
32
- const temProdutosDuplicados = typeof idProdutosDuplicados[0] !== 'undefined'
28
+ const temProdutosDuplicados = isNotUndefined(idProdutosDuplicados[0])
33
29
  if (temProdutosDuplicados) {
34
30
  return res.status(400).send({ message: constant.CARRINHO_COM_PRODUTO_DUPLICADO, idProdutosDuplicados })
35
31
  }
36
32
 
37
- const produtos = req.body.produtos
38
- for (let index = 0; index < produtos.length; index++) {
39
- produtos[index].quantidade = parseInt(produtos[index].quantidade)
40
- const { idProduto, quantidade } = produtos[index]
41
- if (!await produtosService.existeProduto({ _id: idProduto })) {
42
- return res.status(400).send({ message: constant.IDPRODUTO_INVALIDO, item: { index, idProduto, quantidade } })
33
+ const { produtos } = req.body
34
+ const produtosComPrecoUnitario = []
35
+ for (const produto of produtos) {
36
+ const { precoUnitario: preco, error } = await produtosService.getPrecoUnitarioOuErro(produto)
37
+ if (error) {
38
+ const index = produtos.indexOf(produto)
39
+ const item = { ...error.item, index }
40
+ return res.status(error.statusCode).send({ message: error.message, item })
43
41
  }
44
-
45
- const { quantidade: quantidadeEstoque, preco } = await produtosService.getDadosDoProduto({ _id: idProduto })
46
- if (quantidade > quantidadeEstoque) {
47
- return res.status(400).send({ message: constant.ESTOQUE_INSUFICIENTE, item: { index, idProduto, quantidade, quantidadeEstoque } })
48
- }
49
- Object.assign(produtos[index], { precoUnitario: preco })
50
- }
51
- let precoTotal = 0
52
- let quantidadeTotal = 0
53
- for (let index = 0; index < produtos.length; index++) {
54
- const { idProduto, quantidade } = produtos[index]
55
- const { quantidade: quantidadeEmEstoque, preco } = await produtosService.getDadosDoProduto({ _id: idProduto })
56
- const novaQuantidade = quantidadeEmEstoque - quantidade
57
- await produtosService.updateById(idProduto, { $set: { quantidade: novaQuantidade } })
58
- precoTotal += preco * quantidade
59
- quantidadeTotal += quantidade
42
+ produtosComPrecoUnitario.push({ ...produto, precoUnitario: preco })
60
43
  }
44
+ const precoTotal = await service.precoTotal(produtosComPrecoUnitario)
45
+ const quantidadeTotal = await service.quantidadeTotal(produtosComPrecoUnitario)
61
46
 
62
- Object.assign(req.body, { precoTotal, quantidadeTotal, idUsuario: _id })
47
+ const carrinho = { produtos: produtosComPrecoUnitario, precoTotal, quantidadeTotal, idUsuario }
63
48
 
64
- const dadosCadastrados = await service.criarCarrinho(req.body)
49
+ const dadosCadastrados = await service.criarCarrinho(carrinho)
65
50
  res.status(201).send({ message: constant.POST_SUCESS, _id: dadosCadastrados._id })
66
51
  }
67
52
 
68
53
  exports.cancelarCompra = async (req, res) => {
69
54
  const carrinhoDoUsuario = await service.getCarrinhoDoUsuario(req.headers.authorization)
70
- const usuarioTemCarrinho = typeof carrinhoDoUsuario[0] !== 'undefined'
55
+ const usuarioTemCarrinho = isNotUndefined(carrinhoDoUsuario[0])
71
56
 
72
57
  if (usuarioTemCarrinho) {
73
58
  const produtos = carrinhoDoUsuario[0].produtos
@@ -87,10 +72,14 @@ exports.cancelarCompra = async (req, res) => {
87
72
 
88
73
  exports.concluirCompra = async (req, res) => {
89
74
  const carrinhoDoUsuario = await service.getCarrinhoDoUsuario(req.headers.authorization)
90
- const usuarioTemCarrinho = typeof carrinhoDoUsuario[0] !== 'undefined'
75
+ const usuarioTemCarrinho = isNotUndefined(carrinhoDoUsuario[0])
91
76
  if (usuarioTemCarrinho) {
92
77
  await service.deleteById(carrinhoDoUsuario[0]._id)
93
78
  return res.status(200).send({ message: constant.DELETE_SUCESS })
94
79
  }
95
80
  res.status(200).send({ message: constant.SEM_CARRINHO })
96
81
  }
82
+
83
+ const isUndefined = (object) => typeof object === 'undefined'
84
+
85
+ const isNotUndefined = (object) => !isUndefined(object)
@@ -1,4 +1,4 @@
1
- const { INTERNAL_ERROR } = require('../utils/constants')
1
+ const { INTERNAL_ERROR, TIMEOUT } = require('../utils/constants')
2
2
  const montarMensagemDeErroDeSchema = require('../utils/montarMensagemDeErroDeSchema')
3
3
 
4
4
  function errorHandler (error, _req, res, _next) {
@@ -10,9 +10,13 @@ function errorHandler (error, _req, res, _next) {
10
10
  if (error.type === 'entity.parse.failed') {
11
11
  console.log('Erro 500')
12
12
  return res.status(500).json({
13
- message: 'Adicione aspas em todos os valores. Esse problema está sendo investigado na issue https://github.com/ServeRest/ServeRest/issues/225'
13
+ message: 'Adicione aspas em todos os valores. Para mais informações acesse a issue https://github.com/ServeRest/ServeRest/issues/225'
14
14
  })
15
15
  }
16
+ /* istanbul ignore if */
17
+ if (error.code === 'ETIMEDOUT') {
18
+ return res.status(408).json({ message: TIMEOUT })
19
+ }
16
20
  return res.status(500).json({ message: INTERNAL_ERROR, error })
17
21
  }
18
22
 
@@ -2,17 +2,36 @@
2
2
 
3
3
  const { RateLimiterMemory } = require('rate-limiter-flexible')
4
4
 
5
+ const { aplicacaoExecutandoLocalmente } = require('../utils/ambiente')
6
+
5
7
  const rateLimiter = new RateLimiterMemory({
6
- points: 150, // requests
7
- duration: 1 // segundo por IP
8
+ points: 250, // requests
9
+ duration: 2 // segundo por IP
8
10
  })
9
11
 
10
- // Adicionar header 'monitor: false' quando atingir o limite definido para não enviar informações para o moesif.
12
+ // Irá retornar mensagem de erro se o teste de carga:
13
+ // 1. Estiver sendo executado em localhost sem o header 'monitor'.
14
+ // 2. Estiver sendo executado fora de localhost.
11
15
  module.exports = async (req, res, next) => {
16
+ const reqContainsHeaderMonitor = req.rawHeaders.includes('monitor')
17
+
18
+ const messageLoadTest = 'Foi detectado comportamento equivalente a teste de carga'
19
+ const messageAdjust = 'Leia a seção sobre teste de carga https://github.com/ServeRest/ServeRest#teste-de-carga e faça o ajuste necessário.'
20
+
12
21
  await rateLimiter.consume(req.ip)
13
22
  .then(() => next())
14
23
  .catch(() => {
15
- req.headers.monitor = false
24
+ if (aplicacaoExecutandoLocalmente()) {
25
+ if (!reqContainsHeaderMonitor) {
26
+ return res.status(429).send({
27
+ message: `${messageLoadTest} com ausência do header 'monitor'. ${messageAdjust}`
28
+ })
29
+ }
30
+ } else {
31
+ return res.status(429).send({
32
+ message: `${messageLoadTest}. ${messageAdjust}`
33
+ })
34
+ }
16
35
  next()
17
36
  })
18
37
  }
@@ -6,6 +6,7 @@ const { join } = require('path')
6
6
  const alterarValoresParaRegex = require('../utils/alterarValoresParaRegex')
7
7
  const authService = require('../services/auth-service')
8
8
  const usuariosService = require('../services/usuarios-service')
9
+ const produtosService = require('../services/produtos-service')
9
10
 
10
11
  const datastore = Datastore.create({ filename: join(__dirname, '../data/carrinhos.db'), autoload: true })
11
12
 
@@ -42,7 +43,33 @@ exports.deleteById = async id => {
42
43
  }
43
44
 
44
45
  exports.getCarrinhoDoUsuario = async (authorization) => {
46
+ const _id = await idUsuario(authorization)
47
+ return this.getAll({ idUsuario: _id })
48
+ }
49
+
50
+ exports.usuarioJaPossuiCarrinho = async (authorization) => {
51
+ const _id = await idUsuario(authorization)
52
+ return {
53
+ idUsuario: _id,
54
+ possuiCarrinho: await this.existeCarrinho({ idUsuario: _id })
55
+ }
56
+ }
57
+
58
+ exports.precoTotal = async (produtos) => {
59
+ return produtos.reduce(async (precoAnterior, produto) => {
60
+ return (await precoAnterior) + produto.precoUnitario * produto.quantidade
61
+ }, Promise.resolve(0))
62
+ }
63
+
64
+ exports.quantidadeTotal = async (produtos) => {
65
+ return produtos.reduce(async (quantidadeAnterior, produto) => {
66
+ await produtosService.updateQuantidade(produto)
67
+ return (await quantidadeAnterior) + produto.quantidade
68
+ }, Promise.resolve(0))
69
+ }
70
+
71
+ const idUsuario = async (authorization) => {
45
72
  const { email, password } = authService.verifyToken(authorization)
46
- const { _id: idUsuario } = await usuariosService.getDadosDoUsuario({ email, password })
47
- return this.getAll({ idUsuario })
73
+ const { _id } = await usuariosService.getDadosDoUsuario({ email, password })
74
+ return _id
48
75
  }
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const constant = require('../utils/constants')
3
4
  const Datastore = require('nedb-promises')
4
5
  const { join } = require('path')
5
6
 
@@ -24,11 +25,32 @@ exports.existeProduto = pesquisa => {
24
25
  return datastore.count(pesquisa)
25
26
  }
26
27
 
28
+ exports.updateQuantidade = async ({ idProduto, quantidade }) => {
29
+ const { quantidade: quantidadeEmEstoque } = await this.getDadosDoProduto({ _id: idProduto })
30
+ const novaQuantidade = quantidadeEmEstoque - quantidade
31
+ await this.updateById(idProduto, { $set: { quantidade: novaQuantidade } })
32
+ }
33
+
27
34
  exports.criarProduto = async body => {
28
35
  body = formatarValores(body)
29
36
  return datastore.insert(body)
30
37
  }
31
38
 
39
+ exports.getPrecoUnitarioOuErro = async (produto) => {
40
+ const quantidade = parseInt(produto.quantidade)
41
+ const { idProduto } = produto
42
+ const existePedido = await this.existeProduto({ _id: idProduto })
43
+ if (!existePedido) {
44
+ return { error: { statusCode: 400, message: constant.IDPRODUTO_INVALIDO, item: { idProduto, quantidade } } }
45
+ }
46
+
47
+ const { quantidade: quantidadeEstoque, preco } = await this.getDadosDoProduto({ _id: idProduto })
48
+ if (quantidade > quantidadeEstoque) {
49
+ return { error: { statusCode: 400, message: constant.ESTOQUE_INSUFICIENTE, item: { idProduto, quantidade, quantidadeEstoque } } }
50
+ }
51
+ return { precoUnitario: preco }
52
+ }
53
+
32
54
  exports.deleteById = async id => {
33
55
  return datastore.remove({ _id: id }, {})
34
56
  }
@@ -5,24 +5,32 @@ const { conf } = require('./conf')
5
5
  function formaDeExecucao () {
6
6
  if (process.env.USERNAME === 'docker' ||
7
7
  process.env.USERNAME === 'serverest.dev' ||
8
+ process.env.USERNAME === 'staging.serverest.dev' ||
8
9
  process.env.USERNAME === 'agilizei') {
9
10
  return process.env.USERNAME
10
11
  }
11
12
  return 'npm'
12
13
  }
13
14
 
15
+ const aplicacaoExecutandoLocalmente = () => {
16
+ return (formaDeExecucao() === 'npm' || formaDeExecucao() === 'docker')
17
+ }
18
+
14
19
  function urlDocumentacao () {
15
20
  switch (formaDeExecucao()) {
16
21
  case 'serverest.dev':
17
22
  return 'https://serverest.dev'
23
+ case 'staging.serverest.dev':
24
+ return 'https://staging.serverest.dev'
18
25
  case 'agilizei':
19
- return 'https://serverest-api.agilizei.com/'
26
+ return 'https://agilizei.serverest.dev'
20
27
  default:
21
28
  return `http://localhost:${conf.porta}`
22
29
  }
23
30
  }
24
31
 
25
32
  module.exports = {
33
+ aplicacaoExecutandoLocalmente,
26
34
  formaDeExecucao,
27
35
  urlDocumentacao
28
36
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  module.exports = {
4
4
  INTERNAL_ERROR: 'Abra uma issue informando essa resposta. https://github.com/ServeRest/ServeRest/issues',
5
+ TIMEOUT: 'Timeout da requisição atingido',
5
6
  POST_SUCESS: 'Cadastro realizado com sucesso',
6
7
  DELETE_SUCESS: 'Registro excluído com sucesso',
7
8
  DELETE_NONE: 'Nenhum registro excluído',
@@ -38,6 +38,7 @@ module.exports = async app => {
38
38
  req.originalUrl === '/swagger-ui-bundle.js.map' ||
39
39
  req.headers.monitor ||
40
40
  (formaDeExecucao() === 'serverest.dev' && req.originalUrl === '/') ||
41
+ (formaDeExecucao() === 'staging.serverest.dev' && req.originalUrl === '/') ||
41
42
  (formaDeExecucao() === 'agilizei' && req.originalUrl === '/')) {
42
43
  return true
43
44
  }