diff --git a/.env.example b/.env.example
deleted file mode 100644
index e66a4d53..00000000
--- a/.env.example
+++ /dev/null
@@ -1 +0,0 @@
-VITE_API_URL=http://127.0.0.1:5001/api
\ No newline at end of file
diff --git a/README.md b/README.md
index 9b8f6404..c5d46b9e 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
+# 🚀 Guia de Integração do Frontend
+
+Este guia explica como configurar, estruturar e integrar o frontend do projeto React com o backend Flask.
+
+---
+
# ESS Front-end React
This is the Front-end base project in React for the Software and Systems Engineering discipline, offered by the Informatics Center (CIn) of the Federal University of Pernambuco (UFPE).
@@ -46,6 +52,26 @@ npm run
This project uses `.env` files to manage environment variables. You can create a `.env.development` file in the project directory and set the environment variables in the file (iou can create it from .`env.example`). The `env` script in the `package.json` file uses the `env-cmd` package to load the environment variables from the `.env.development` file.
+Crie um arquivo .env na raiz do frontend e adicione a URL da API:
+```
+VITE_API_URL=http://127.0.0.1:5000
+```
+
+📂 src/ → Código-fonte do projeto │
+├── 📂 app/ → Páginas principais (leva a estilização das telas) │ ├── 📂 home/ │ │ ├── 📂 pages/ │ │ │ ├── Login.tsx → Tela de Login │ │ │ ├── Cadastro.tsx → Tela de Cadastro │ │ │ ├── Reservas.tsx → Tela após login │
+├── 📂 shared/ → Recursos compartilhados │ ├── 📂 services/ → Serviços de integração com a API │ │ ├── autorizacao.tsx → Requisições de login/cadastro │
+├── App.tsx → Arquivo principal do React onde você adiciona suas rotas criadas nas pages! ├── main.tsx → Ponto de entrada da aplicação │ ├── .env → Configuração da API ├── package.json → Lista de dependências ├── README.md → Você está aqui! 📌
+
+Endereço para se colocar as estilizações próprias de cada tela.
+```
+src\app\home\styles
+```
+
+Endereço onde se pode colocar arquivos css em comum ao sistema
+```
+src\shared\components
+```
+
### Running the App
To start the app, run the following command:
@@ -56,6 +82,73 @@ npm run dev
This command will run the React app in development with Vite.js script
+
+
+## Rodando o backend Flask
+
+No powerShell mude para o diretório backend
+```
+cd backend
+```
+Crie arquivos __init__.py em todos diretórios dentro de backend, inclusive nele.
+
+backend/
+ __init__.py
+ main.py
+ testes/
+ __init__.py
+ teste_exemplo.py
+
+MacOS
+Dentro da pasta backend no terminal, execute os seguintes comandos:
+
+```
+export PYTHONPATH=$(pwd)/backend
+export FLASK_APP=main
+flask run
+```
+
+Dentro da pasta backend/testes, execute:
+
+```
+export PYTHONPATH=$(pwd)/backend
+pytest
+Windows (Powershell)
+```
+Dentro da pasta backend no PowerShell, execute os seguintes comandos:
+
+```
+$env:PYTHONPATH = "$(pwd)/backend"
+$env:FLASK_APP = "main"
+flask run
+```
+
+
+Crie a venv
+```
+python -m venv venv
+```
+Ative a venv
+```
+venv\Scripts\activate
+```
+e agora você deve instalar todas as dependencias do projeto
+
+```
+pip install -r requirements.txt
+```
+
+obs: caso sejam necessárias novas bibliotecas e deseja atualizar o requirements.txt por favor recirar arquivo.
+```
+pip freeze > requirements.txt
+```
+
+Rodando servidor Flask localmente na rota 5000.
+```
+python main.py
+```
+
+
## Running the tests
There are two types of tests configured in the base project: unit tests using Vitest with React Testing Library and E2E acceptance tests using Cypress with Cucumber. It's interesting to create the **.env.testing** at the root of the project the same way it was created to run in development, changing the necessary values.
diff --git a/backend/__init__.py b/backend/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/__pycache__/__init__.cpython-313.pyc b/backend/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 00000000..0ee68d70
Binary files /dev/null and b/backend/__pycache__/__init__.cpython-313.pyc differ
diff --git a/backend/__pycache__/blueprints.cpython-313.pyc b/backend/__pycache__/blueprints.cpython-313.pyc
new file mode 100644
index 00000000..6a4384cd
Binary files /dev/null and b/backend/__pycache__/blueprints.cpython-313.pyc differ
diff --git a/backend/__pycache__/config.cpython-313.pyc b/backend/__pycache__/config.cpython-313.pyc
new file mode 100644
index 00000000..6e4f1e8f
Binary files /dev/null and b/backend/__pycache__/config.cpython-313.pyc differ
diff --git a/backend/__pycache__/main.cpython-313.pyc b/backend/__pycache__/main.cpython-313.pyc
new file mode 100644
index 00000000..faa7a7fe
Binary files /dev/null and b/backend/__pycache__/main.cpython-313.pyc differ
diff --git a/backend/blueprints.py b/backend/blueprints.py
new file mode 100644
index 00000000..60bd1df5
--- /dev/null
+++ b/backend/blueprints.py
@@ -0,0 +1,38 @@
+from backend.rotas.login import login_bp
+from backend.rotas.cadastro import cadastro_bp
+from backend.rotas.logout import logout_bp
+from backend.rotas.criar_solicitacao_manutencao import criar_manutencao_bp
+from backend.rotas.criar_solicitacao_recursos import criar_recursos_bp
+from backend.rotas.excluir_solicitacao_manutencao import excluir_manutencao_bp
+from backend.rotas.excluir_solicitacao_recursos import excluir_recursos_bp
+from backend.rotas.editar_solicitacao_manutencao import editar_manutencao_bp
+from backend.rotas.editar_solicitacao_recursos import editar_recursos_bp
+from backend.rotas.reservas import reservas_bp
+from backend.rotas.salas import salas_bp
+from backend.rotas.usuario import usuarios_bp
+from backend.rotas.criarReview import criar_review_bp
+from backend.rotas.atualizarReview import atualizar_review_bp
+from backend.rotas.deletarReview import deletar_review_bp
+from backend.rotas.obterReview import obter_review_bp
+from backend.rotas.listarReview import listar_reviews_bp
+from flask_cors import CORS
+
+# Registra os Blueprints
+def registrarBlueprints(app):
+ blueprints = [
+ login_bp, cadastro_bp, logout_bp, criar_manutencao_bp, criar_recursos_bp, excluir_manutencao_bp, excluir_recursos_bp, editar_recursos_bp, editar_manutencao_bp,
+ salas_bp, usuarios_bp, reservas_bp, criar_review_bp, listar_reviews_bp, obter_review_bp, deletar_review_bp, atualizar_review_bp
+ ]
+
+ for blueprint in blueprints:
+ CORS(blueprint)
+ app.register_blueprint(blueprint)
+
+ CORS(app, supports_credentials=True)
+
+ @app.after_request
+ def add_cors_headers(response):
+ response.headers["Access-Control-Allow-Origin"] = "*"
+ response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
+ response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
+ return response
\ No newline at end of file
diff --git a/backend/config.py b/backend/config.py
new file mode 100644
index 00000000..f7e562c4
--- /dev/null
+++ b/backend/config.py
@@ -0,0 +1,7 @@
+import os
+
+class Config:
+ SECRET_KEY = os.urandom(24)
+ SQLALCHEMY_DATABASE_URI = "sqlite:///users.db"
+ SQLALCHEMY_TRACK_MODIFICATIONS = False
+
diff --git a/backend/features/atualizarReview.feature b/backend/features/atualizarReview.feature
new file mode 100644
index 00000000..f9d85f05
--- /dev/null
+++ b/backend/features/atualizarReview.feature
@@ -0,0 +1,13 @@
+Feature: Atualizar avaliação
+
+ Scenario: Atualizar uma avaliação existente
+ Given o professor Suruagy deseja editar uma avaliação feita anteriormente
+ When ele envia uma requisição PUT "/api/reviews/1" especificando o id "1" da avaliação que deseja editar
+ And modifica a nota de "4" para "5" e o comentário de "Sala boa, mas com algumas falhas." para "Modificações feitas, a sala está impecável agora!"
+ Then o sistema retorna a mensagem "Avaliação atualizada com sucesso." e o status 200 OK
+
+ Scenario: Tentar atualizar uma avaliação que não existe
+ Given o professor Suruagy deseja editar uma avaliação cuja qual não está presente no sistema
+ When ele envia uma requisição PUT "/api/reviews/1" especificando o id "1" da avaliação que deseja editar
+ And modifica a nota de "4" para "5" e o comentário de "Sala boa, mas com algumas falhas." para "Falhas corrigidas, a sala está impecável!"
+ Then o sistema retorna a mensagem "Avaliação não encontrada para o ID fornecido." e o status 404 NOT FOUND
diff --git a/backend/features/cadastroServico.feature b/backend/features/cadastroServico.feature
new file mode 100644
index 00000000..09f2c1ce
--- /dev/null
+++ b/backend/features/cadastroServico.feature
@@ -0,0 +1,100 @@
+Feature: Serviço de Cadastro de Usuários
+
+ Scenario: Sucesso no cadastro de usuário
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "Demosténes"
+ And ele informa o CPF "126.455.789-00"
+ And ele informa o email "demostenessouza@example.com"
+ And ele informa se é professor "N"
+ And ele informa a senha "SecurePassword123"
+ And ele informa a confirmação da senha "SecurePassword123"
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "Cadastro criado com sucesso!"
+ And o status code deve ser "201"
+
+ Scenario: Sucesso no cadastro de professor
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "Tatiana"
+ And ele informa o CPF "331.879.789-33"
+ And ele informa o email "vanessasilva@example.com"
+ And ele informa se é professor "S"
+ And ele informa o SIAPE "101110"
+ And ele informa a senha "12345678"
+ And ele informa a confirmação da senha "12345678"
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "Cadastro criado com sucesso!"
+ And o status code deve ser "201"
+
+ Scenario: Fracasso no cadastro por campos obrigatórios não preenchidos
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "João"
+ And ele informa o CPF "987.654.321-00"
+ And ele informa o email "joao@iat.com"
+ And ele informa se é professor "N"
+ And ele informa a senha "Password123"
+ And ele deixa o campo "Confirmar Senha" com ""
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "Confirmar Senha é obrigatório."
+ And o status code deve ser "400"
+
+ Scenario: Fracasso no cadastro por duplicação de ID única
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "Carlos Mendes"
+ And ele informa o CPF "126.456.789-00"
+ And ele informa o email "demostenes@example.com"
+ And ele informa se é professor "S"
+ And ele informa o SIAPE "010101"
+ And ele informa a senha "Password456"
+ And ele informa a confirmação da senha "Password456"
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "Erro: email/cpf já está registrado."
+ And o status code deve ser "409"
+
+ Scenario: Fracasso no cadastro por senhas que não coincidem
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "Beatriz"
+ And ele informa o CPF "789.456.123-00"
+ And ele informa o email "Beatriz.oliveira@example.com"
+ And ele informa se é professor "N"
+ And ele informa a senha "MyPassword123"
+ And ele informa a confirmação da senha "DifferentPassword123"
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "As senhas não coincidem."
+ And o status code deve ser "400"
+
+ Scenario: Fracasso no cadastro por formato inválido de email
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "Lucas"
+ And ele informa o CPF "987.654.321-00"
+ And ele informa o email "lucas.example.com"
+ And ele informa se é professor "N"
+ And ele informa a senha "SenhaForte123"
+ And ele informa a confirmação da senha "SenhaForte123"
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "Formato de email inválido. Use um email válido, como exemplo@dominio.com."
+ And o status code deve ser "400"
+
+ Scenario: Fracasso no cadastro por formato inválido de CPF
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "Fabricio"
+ And ele informa o CPF "123"
+ And ele informa o email "fabricio@example.com"
+ And ele informa se é professor "N"
+ And ele informa a senha "SenhaSegura456"
+ And ele informa a confirmação da senha "SenhaSegura456"
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "CPF inválido. Digite um CPF válido no formato XXX.XXX.XXX-XX."
+ And o status code deve ser "400"
+
+ Scenario: Fracasso no cadastro por siape já registrado
+ Given o usuário deseja se cadastrar
+ When ele informa o nome "Max"
+ And ele informa o CPF "987.654.321-00"
+ And ele informa o email "max@gmail.com"
+ And ele informa se é professor "S"
+ And ele informa o SIAPE "101010"
+ And ele informa a senha "Senha123"
+ And ele informa a confirmação da senha "Senha123"
+ And ele envia uma requisição POST para "/cadastro"
+ Then a resposta deve conter a mensagem "Erro: siape já está registrado."
+ And o status code deve ser "409"
\ No newline at end of file
diff --git a/backend/features/criarReview.feature b/backend/features/criarReview.feature
new file mode 100644
index 00000000..06b0c7ba
--- /dev/null
+++ b/backend/features/criarReview.feature
@@ -0,0 +1,26 @@
+Feature: Criação de Review
+
+ Scenario: Criação bem-sucedida de review
+ Given que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id "1" para a sala_id "2"
+ When ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "2", usuario_id "3", nota "4" e comentário "Sala boa, mas com algumas falhas."
+ Then o sistema retorna "Avaliação criada com sucesso!" com o status 201
+
+ Scenario: Falha ao criar review sem nota
+ Given que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id "1" para a sala_id "2"
+ When ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "2", usuario_id "3", nota "" e comentário "Sala boa, mas sem computador!"
+ Then o sistema retorna "A nota é obrigatória para avaliar a sala." com o status 400
+
+ Scenario: Falha ao criar review sem sala_id
+ Given que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id "1" para a sala_id ""
+ When ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "", usuario_id "3", nota "4" e comentário "Sala boa, mas sem computador!"
+ Then o sistema retorna "O ID da Sala é obrigatório para avaliar a sala." com o status 400
+
+ Scenario: Falha ao criar review sem usuario_id
+ Given que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id "1" para a sala_id "2"
+ When ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "2", usuario_id "", nota "4" e comentário "Sala boa, mas sem computador!"
+ Then o sistema retorna "O ID do Usuário é obrigatório para avaliar a sala." com o status 400
+
+ Scenario: Falha ao criar review sem reserva_id
+ Given que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id ""
+ When ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "", sala_id "2", usuario_id "3", nota "4" e comentário "Sala boa, mas sem computador!"
+ Then o sistema retorna "O ID da Reserva é obrigatório para avaliar a sala." com o status 400
diff --git a/backend/features/deletarReview.feature b/backend/features/deletarReview.feature
new file mode 100644
index 00000000..67057a23
--- /dev/null
+++ b/backend/features/deletarReview.feature
@@ -0,0 +1,11 @@
+Feature: Deletar Avaliação
+
+ Scenario: Deletar avaliação existente
+ Given o professor Suruagy deseja deletar uma avaliação feita anteriormente
+ When ele envia uma requisição DELETE para "/api/reviews/1" especificando o id "1" da avaliação que deseja deletar
+ Then o sistema retorna a mensagem "Avaliação deletada com sucesso!" e o status 200 OK
+
+ Scenario: Deletar avaliação que não existe
+ Given o professor Suruagy deseja deletar uma avaliação que não existe
+ When ele envia uma requisição DELETE para "/api/reviews/1" especificando o id "1" da avaliação que deseja deletar
+ Then o sistema retorna a mensagem "Avaliação não encontrada para o ID fornecido." e o status 404 NOT FOUND
diff --git a/backend/features/listarReview.feature b/backend/features/listarReview.feature
new file mode 100644
index 00000000..f2d76e89
--- /dev/null
+++ b/backend/features/listarReview.feature
@@ -0,0 +1,12 @@
+Feature: Listar Avaliações
+
+ Scenario: Listar avaliações quando há avaliações no sistema
+ Given o professor Suruagy deseja consultar as avaliações presentes no sistema e existem avaliações cadastradas
+ When ele envia uma requisição GET para "/api/reviews"
+ Then o sistema lista todas as avaliações que foram postadas anteriormente para todas as salas com o status 200 OK
+
+ Scenario: Listar avaliações quando não há nenhuma avaliação
+ Given o professor Suruagy deseja consultar as avaliações presentes no sistema e não existem avaliações cadastradas
+ When ele envia uma requisição GET para "/api/reviews"
+ Then o sistema não encontra nenhuma avaliação no sistema
+ And exibe a mensagem de erro "Nenhuma avaliação encontrada." com o status 404 NOT FOUND
diff --git a/backend/features/loginServico.feature b/backend/features/loginServico.feature
new file mode 100644
index 00000000..07541119
--- /dev/null
+++ b/backend/features/loginServico.feature
@@ -0,0 +1,21 @@
+Feature: Autenticação de usuários
+
+ Scenario: Sucesso no login
+ Given o usuário possui o email "demostenes@example.com" e a senha "SecurePassword123" válidos
+ When ele envia uma requisição POST para "/api/login" com os dados "demostenes@example.com" e "SecurePassword123"
+ Then a resposta deve conter o email "demostenes@example.com" e a mensagem "success" igual a True
+ And o status code deve ser "200"
+
+ Scenario: Fracasso no login por senha incorreta
+ Given o usuário possui o email "demostenes@example.com" válido e a senha "SecureIncorreta123" inválida
+ When ele envia uma requisição POST para "/api/login" com os dados "demostenes@example.com" e "SecureIncorreta123"
+ Then a resposta deve conter a mensagem "Usuário ou senha inválidos."
+ And o status code deve ser "401"
+
+ Scenario: Fracasso no login por falta de email ou senha
+ Given o usuário envia uma requisição sem email ou senha
+ When ele envia uma requisição POST para "/api/login" com os dados " " e " "
+ Then a resposta deve conter a mensagem "Usuário e senha são obrigatórios."
+ And o status code deve ser "400"
+
+
\ No newline at end of file
diff --git a/backend/features/manutencao.feature b/backend/features/manutencao.feature
new file mode 100644
index 00000000..9121bc97
--- /dev/null
+++ b/backend/features/manutencao.feature
@@ -0,0 +1,28 @@
+Feature: Criar/remover solicitação de manutenção de sala
+
+ Scenario: sucesso ao criar uma solicitação de manutenção para uma reserva concluída
+ Given o professor possui uma reserva de sala reserva_id "1" que já foi encerrada
+ When ele envia uma requisição POST /solicitacoes/manutencao com os dados: reserva_id: "1", descricao: "Mesa quebrada."
+ Then o sistema retorna "mensagem" "Parabéns, sua solicitação de manutenção foi criada!" e um status "201"
+ And a reserva reserva_id: "1" possui uma solicitação de manutenção com descricao: "Mesa quebrada."
+
+ Scenario: fracasso ao criar uma solicitação de manutenção sem preencher o campo descricao
+ Given o professor possui uma reserva de sala reserva_id "1" que já foi encerrada
+ When ele envia uma requisição POST /solicitacoes/manutencao com os dados: reserva_id: "1", descricao: " "
+ Then o sistema retorna "erro" "O campo 'descricao' não pode estar vazio." e um status "400"
+
+ Scenario: sucesso ao editar uma solicitação de manutenção existente
+ Given o professor já criou uma solicitação de manutenção associada a reserva_id "1"
+ When ele envia uma requisição PUT /solicitacoes/manutencao/"1" contendo o ID da solicitação de manutenção e a alteração descricao: "Mesa e cadeira quebradas."
+ Then o sistema retorna "mensagem" "Solicitação de manutenção atualizada com sucesso" e um status "200"
+ And o sistema atualiza os detalhes da solicitação com descricao: "Mesa e cadeira quebradas."
+
+ Scenario: fracasso ao editar solicitação de manutenção sem preencher o campo descricao
+ Given o professor já criou uma solicitação de manutenção associada a reserva_id "1"
+ When ele envia uma requisição PUT /solicitacoes/manutencao/"1" contendo o ID da solicitação de manutenção e a alteração descricao: " "
+ Then o sistema retorna "erro" "A descrição da manutenção não pode ser vazia" e um status "400"
+
+ Scenario: sucesso ao excluir uma solicitação de manutenção existente
+ Given o professor já criou uma solicitação de manutenção associada a reserva_id "1"
+ When ele envia uma requisição DELETE /solicitacoes/manutencao/"1",
+ Then o sistema remove a solicitação do banco de dados e retorna um status "204"
\ No newline at end of file
diff --git a/backend/features/obterReview.feature b/backend/features/obterReview.feature
new file mode 100644
index 00000000..a0be4c7e
--- /dev/null
+++ b/backend/features/obterReview.feature
@@ -0,0 +1,12 @@
+Feature: Consultar Avaliação
+
+ Scenario: Consulta de avaliação existente
+ Given o professor Suruagy deseja consultar uma avaliação presente no sistema
+ When ele envia uma requisição GET para "/api/reviews/1"
+ Then o sistema retorna a avaliação com comentário "Sala excelente, as mudanças foram feitas e ficou ótima.", data_avaliacao "Sat, 15 Feb 2025 16:31:37 GMT", id "1", nota "5", reserva_id "1", sala_id "2", usuario_id "3" com o status 200 OK
+
+ Scenario: Consulta de avaliação inexistente
+ Given o professor Suruagy deseja consultar uma avaliação presente no sistema
+ When ele envia uma requisição GET para "/api/reviews/1"
+ Then o sistema não encontra avaliação presente com o ID especificado
+ And retorna a mensagem de erro "Avaliação não encontrada para o ID fornecido." com o status 404 NOT FOUND
diff --git a/backend/features/recursos.feature b/backend/features/recursos.feature
new file mode 100644
index 00000000..3861f897
--- /dev/null
+++ b/backend/features/recursos.feature
@@ -0,0 +1,57 @@
+Feature: Criar/remover solicitação de recursos de sala
+
+ Scenario: sucesso ao criar solicitação de recursos para uma reserva ativa com todos os campos preenchidos
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: "Projetor, Teclado", itens_nao_listados: "Extensão elétrica", observacoes: "Para aula prática"
+ Then o sistema retorna "mensagem" "Parabéns, sua solicitação de recursos foi criada!" e um status "201"
+ And a reserva_id "1" possui uma solicitação com recursos "Projetor, Teclado", itens_nao_listados "Extensão elétrica" e observacoes "Para aula prática"
+
+ Scenario: fracasso ao criar solicitação de recursos com campos preenchidos com espaços ou não preenchidos
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: " ", itens_nao_listados: " ", observacoes: " "
+ Then o sistema retorna "erro" "Você deve selecionar um recurso ou especificar itens não listados." e um status "400"
+
+ Scenario: fracasso ao criar solicitação de recursos com apenas o campo observacoes preenchido
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: " ", itens_nao_listados: " ", observacoes: "Para aula prática"
+ Then o sistema retorna "erro" "Você deve selecionar um recurso ou especificar itens não listados." e um status "400"
+
+ Scenario: sucesso ao criar solicitação de recursos sem preencher o campo itens_nao_listados
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: "Projetor, Teclado", itens_nao_listados: " ", observacoes: "Para aula prática"
+ Then o sistema retorna "mensagem" "Parabéns, sua solicitação de recursos foi criada!" e um status "201"
+ And a reserva_id "1" possui uma solicitação com recursos "Projetor, Teclado", itens_nao_listados " " e observacoes "Para aula prática"
+
+ Scenario: sucesso ao criar solicitação de recursos sem preencher o campo itens_nao_listados e o campo observacoes
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: "Projetor, Teclado", itens_nao_listados: " ", observacoes: " "
+ Then o sistema retorna "mensagem" "Parabéns, sua solicitação de recursos foi criada!" e um status "201"
+ And a reserva_id "1" possui uma solicitação com recursos "Projetor, Teclado", itens_nao_listados " " e observacoes " "
+
+ Scenario: sucesso ao criar solicitação de recursos com o campo de recursos vazio e apenas especificando os itens não listados
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: " ", itens_nao_listados: "Extensão elétrica", observacoes: " "
+ Then o sistema retorna "mensagem" "Parabéns, sua solicitação de recursos foi criada!" e um status "201"
+ And a reserva_id "1" possui uma solicitação com recursos " ", itens_nao_listados "Extensão elétrica" e observacoes " "
+
+ Scenario: sucesso ao criar solicitação de recursos com o campo de recursos vazio e especificando os itens não listados e as observacoes
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: " ", itens_nao_listados: "Extensão elétrica", observacoes: "Para aula prática"
+ Then o sistema retorna "mensagem" "Parabéns, sua solicitação de recursos foi criada!" e um status "201"
+ And a reserva_id "1" possui uma solicitação com recursos " ", itens_nao_listados "Extensão elétrica" e observacoes "Para aula prática"
+
+ Scenario: sucesso ao editar uma solicitação de recursos existente
+ Given o professor possui uma solicitação de recursos associada a reserva_id "1"
+ When ele envia uma requisição PUT /solicitacoes/recursos/"1" contendo o ID da solicitação e os novos detalhes da solicitação recursos: "Projetor, Caixas de som", observacoes: "Para evento especial"
+ Then o sistema retorna "mensagem" "Solicitação de recursos atualizada com sucesso" e um status "200"
+ And o sistema atualiza os detalhes da solicitação: recursos: "Projetor, Caixas de som", observacoes: "Para evento especial"
+
+ Scenario: fracasso ao editar uma solicitação de recursos com apenas o campo observacoes preenchido
+ Given o professor possui uma reserva ativa com reserva_id "1"
+ When ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "1", recursos: " ", itens_nao_listados: " ", observacoes: "Para aula prática"
+ Then o sistema retorna "erro" "Você deve selecionar um recurso ou especificar itens não listados." e um status "400"
+
+ Scenario: sucesso ao excluir uma solicitação de recursos existente
+ Given o professor possui uma solicitação de recursos associada a reserva_id "1"
+ When ele envia uma requisição DELETE /solicitacoes/recursos/"1" contendo o ID da solicitação
+ Then o sistema remove a solicitação do banco de dados e retorna um status "204"
\ No newline at end of file
diff --git a/backend/features/reservas.feature b/backend/features/reservas.feature
new file mode 100644
index 00000000..00c45ded
--- /dev/null
+++ b/backend/features/reservas.feature
@@ -0,0 +1,41 @@
+Feature: API de Reservas
+
+ Scenario: Criar uma reserva com sucesso
+ Given a sala de id "5" está disponível no dia "2025-03-03" das "14:00" às "15:00"
+ And o professor de id "3" não tem uma reserva no dia "2025-03-03" das "14:00" às "15:00"
+ When uma requisição "POST" for enviada para "/api/reservas/3" com o corpo: "{"sala_id": 5,"data": "2025-03-03","start_time": "14:00","end_time": "15:00"}"
+ Then o status da resposta deve ser "201"
+ And o JSON da resposta deve conter "mensagem": "Reserva criada com sucesso!"
+ And o JSON da reserva deve conter "sala_id": "5"
+ And o JSON da reserva deve conter "professor_id": "3"
+
+
+ Scenario: Erro ao tentar reservar uma sala já ocupada
+ Given a sala de id "5" não está disponível no dia "2025-02-20" das "14:30" às "16:00"
+ When uma requisição "POST" for enviada para "/api/reservas/3" com o corpo: "{"sala_id": 5,"data": "2025-02-20","start_time": "14:30","end_time": "16:00"}"
+ Then o status da resposta deve ser "409"
+ And o JSON da resposta deve conter "erro": "Sala já reservada para esse horário"
+
+
+ Scenario: Erro ao tentar reservar com campos ausentes
+ Given a sala de id "5" está disponível no dia "2025-01-21" das "14:00" às "15:00"
+ And o professor de id "3" não tem uma reserva no dia "2025-01-21" das "14:00" às "15:00"
+ When uma requisição "POST" for enviada para "/api/reservas/3" com o corpo: "{"data": "2025-01-21","start_time": "14:00","end_time": "15:00"}"
+ Then o status da resposta deve ser "400"
+ And o JSON da resposta deve conter "erro": "Campos obrigatórios ausentes"
+
+
+ Scenario: Cancelar uma reserva com sucesso
+ Given o professor de id "3" tem uma reserva ativa de id "2"
+ When uma requisição "DELETE" for enviada para "/api/reservas/2" com o corpo: """"
+ Then o status da resposta deve ser "200"
+ And o JSON da resposta deve conter "mensagem": "Reserva cancelada!"
+ And o JSON da reserva deve conter "id": "2"
+
+
+ Scenario: Erro ao tentar cancelar uma reserva inexistente
+ When uma requisição "DELETE" for enviada para "/api/reservas/99" com o corpo: """"
+ Then o status da resposta deve ser "404"
+ And o JSON da resposta deve conter "erro": "Reserva não encontrada."
+
+
diff --git a/backend/features/salas.feature b/backend/features/salas.feature
new file mode 100644
index 00000000..1cbc2309
--- /dev/null
+++ b/backend/features/salas.feature
@@ -0,0 +1,43 @@
+Feature: API de Salas
+
+ Scenario: Criar sala com sucesso
+ Given não existe uma sala com nome "E901"
+ When uma requisição "POST" for enviada para "/api/salas" com o corpo: "{"nome": "E901", "tipo": "Reunião", "lugares": 20, "andar": 3, "equipamentos": ["Projetor", "Ar-condicionado"]}"
+ Then o status da resposta deve ser "201"
+ And o JSON da resposta deve conter "mensagem": "Sala criada com sucesso!"
+ And o JSON da sala deve conter "andar": "3"
+ And o JSON da sala deve conter "nome": "E901"
+ And o JSON da sala deve conter "tipo": "Reunião"
+ And o JSON da sala deve conter "lugares": "20"
+
+
+ Scenario: Erro ao tentar criar sala com nome existente
+ Given existe uma sala com nome "E001"
+ When uma requisição "POST" for enviada para "/api/salas" com o corpo: "{"nome": "E001", "tipo": "Reunião", "lugares": 20, "andar": 3, "equipamentos": ["Projetor", "Ar-condicionado"]}"
+ Then o status da resposta deve ser "409"
+ And o JSON da resposta deve conter "erro": "Já existe uma sala com esse nome"
+
+
+ Scenario: Buscar todas as salas disponíveis
+ When uma requisição "GET" for enviada para "/api/salas" com o corpo: """"
+ Then o status da resposta deve ser "200"
+ And o JSON da resposta deve conter uma lista de salas com todos os dados
+
+
+ Scenario: Erro ao buscar salas com tempo não informado
+ When uma requisição "GET" for enviada para "/api/salas?data=2025-02-25&start_time=14:00" com o corpo: """"
+ Then o status da resposta deve ser "400"
+ And o JSON da resposta deve conter "erro": "tempo não informado"
+
+
+ Scenario: Erro ao buscar salas sem data preenchida
+ When uma requisição "GET" for enviada para "/api/salas?start_time=14:00&end_time=15:00" com o corpo: """"
+ Then o status da resposta deve ser "400"
+ And o JSON da resposta deve conter "erro": "data não informada"
+
+
+ Scenario: Erro ao tentar deletar sala com reserva ativa
+ Given a sala de id "1" tem uma reserva ativa
+ When uma requisição "DELETE" for enviada para "/api/salas/1" com o corpo: """"
+ Then o status da resposta deve ser "409"
+ And o JSON da resposta deve conter "erro": "Sala possui reservas ativas e não pode ser deletada"
\ No newline at end of file
diff --git a/backend/instance/users.db b/backend/instance/users.db
new file mode 100644
index 00000000..6b943fea
Binary files /dev/null and b/backend/instance/users.db differ
diff --git a/backend/main.py b/backend/main.py
new file mode 100644
index 00000000..0b986fd7
--- /dev/null
+++ b/backend/main.py
@@ -0,0 +1,29 @@
+from flask import Flask, jsonify
+from flask_cors import CORS
+from backend.blueprints import registrarBlueprints
+from backend.modelo.extensao import db
+from backend.config import Config
+from sqlalchemy import inspect
+
+
+app = Flask(__name__)
+app.config["TESTING"] = True
+app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///users.db"
+app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
+
+CORS(app, origins=["http://localhost:3000"])
+
+db.init_app(app)
+with app.app_context():
+ db.create_all()
+
+
+registrarBlueprints(app)
+
+@app.errorhandler(404)
+def not_found_error(error):
+ return jsonify({"error": "Avaliação não encontrada para o ID fornecido."}), 404
+
+
+if __name__ == "__main__":
+ app.run(debug=True, port=5000)
\ No newline at end of file
diff --git a/backend/modelo/__init__.py b/backend/modelo/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/modelo/__pycache__/__init__.cpython-312.pyc b/backend/modelo/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 00000000..4d586061
Binary files /dev/null and b/backend/modelo/__pycache__/__init__.cpython-312.pyc differ
diff --git a/backend/modelo/__pycache__/__init__.cpython-313.pyc b/backend/modelo/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 00000000..a23be153
Binary files /dev/null and b/backend/modelo/__pycache__/__init__.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/extensao.cpython-312.pyc b/backend/modelo/__pycache__/extensao.cpython-312.pyc
new file mode 100644
index 00000000..41ff179f
Binary files /dev/null and b/backend/modelo/__pycache__/extensao.cpython-312.pyc differ
diff --git a/backend/modelo/__pycache__/extensao.cpython-313.pyc b/backend/modelo/__pycache__/extensao.cpython-313.pyc
new file mode 100644
index 00000000..65a6327d
Binary files /dev/null and b/backend/modelo/__pycache__/extensao.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/reserva.cpython-313.pyc b/backend/modelo/__pycache__/reserva.cpython-313.pyc
new file mode 100644
index 00000000..c1bc466d
Binary files /dev/null and b/backend/modelo/__pycache__/reserva.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/reservas.cpython-313.pyc b/backend/modelo/__pycache__/reservas.cpython-313.pyc
new file mode 100644
index 00000000..70ac1830
Binary files /dev/null and b/backend/modelo/__pycache__/reservas.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/reviewSala.cpython-313.pyc b/backend/modelo/__pycache__/reviewSala.cpython-313.pyc
new file mode 100644
index 00000000..1b67e433
Binary files /dev/null and b/backend/modelo/__pycache__/reviewSala.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/sala.cpython-313.pyc b/backend/modelo/__pycache__/sala.cpython-313.pyc
new file mode 100644
index 00000000..e8efc4f4
Binary files /dev/null and b/backend/modelo/__pycache__/sala.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/salas.cpython-313.pyc b/backend/modelo/__pycache__/salas.cpython-313.pyc
new file mode 100644
index 00000000..2048cb31
Binary files /dev/null and b/backend/modelo/__pycache__/salas.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/solicitacaomanutencao.cpython-312.pyc b/backend/modelo/__pycache__/solicitacaomanutencao.cpython-312.pyc
new file mode 100644
index 00000000..f475de29
Binary files /dev/null and b/backend/modelo/__pycache__/solicitacaomanutencao.cpython-312.pyc differ
diff --git a/backend/modelo/__pycache__/solicitacaomanutencao.cpython-313.pyc b/backend/modelo/__pycache__/solicitacaomanutencao.cpython-313.pyc
new file mode 100644
index 00000000..67e5e247
Binary files /dev/null and b/backend/modelo/__pycache__/solicitacaomanutencao.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/solicitacaorecursos.cpython-312.pyc b/backend/modelo/__pycache__/solicitacaorecursos.cpython-312.pyc
new file mode 100644
index 00000000..71bbff2a
Binary files /dev/null and b/backend/modelo/__pycache__/solicitacaorecursos.cpython-312.pyc differ
diff --git a/backend/modelo/__pycache__/solicitacaorecursos.cpython-313.pyc b/backend/modelo/__pycache__/solicitacaorecursos.cpython-313.pyc
new file mode 100644
index 00000000..b94eeeb4
Binary files /dev/null and b/backend/modelo/__pycache__/solicitacaorecursos.cpython-313.pyc differ
diff --git a/backend/modelo/__pycache__/usuario.cpython-312.pyc b/backend/modelo/__pycache__/usuario.cpython-312.pyc
new file mode 100644
index 00000000..ca14eca7
Binary files /dev/null and b/backend/modelo/__pycache__/usuario.cpython-312.pyc differ
diff --git a/backend/modelo/__pycache__/usuario.cpython-313.pyc b/backend/modelo/__pycache__/usuario.cpython-313.pyc
new file mode 100644
index 00000000..4c2220c8
Binary files /dev/null and b/backend/modelo/__pycache__/usuario.cpython-313.pyc differ
diff --git a/backend/modelo/extensao.py b/backend/modelo/extensao.py
new file mode 100644
index 00000000..f0b13d6f
--- /dev/null
+++ b/backend/modelo/extensao.py
@@ -0,0 +1,3 @@
+from flask_sqlalchemy import SQLAlchemy
+
+db = SQLAlchemy()
diff --git a/backend/modelo/reserva.py b/backend/modelo/reserva.py
new file mode 100644
index 00000000..109872b0
--- /dev/null
+++ b/backend/modelo/reserva.py
@@ -0,0 +1,21 @@
+from backend.modelo.extensao import db
+from datetime import datetime
+
+# Definindo a tabela de Reservas
+class Reserva(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ usuario_id = db.Column(db.Integer, db.ForeignKey('Usuario.id'), nullable=False)
+ sala_id = db.Column(db.Integer, db.ForeignKey('sala.id'), nullable=False)
+ data_reserva = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
+ data_inicio = db.Column(db.DateTime, nullable=False)
+ data_fim = db.Column(db.DateTime, nullable=False)
+ status = db.Column(db.String(50), nullable=False, default='pendente')
+ created_at = db.Column(db.DateTime, default=datetime.utcnow)
+ updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
+
+ # Relacionamentos
+ usuario = db.relationship('Usuario', backref=db.backref('reservas', lazy=True))
+ sala = db.relationship('Sala', backref=db.backref('reservas', lazy=True))
+
+ def __repr__(self):
+ return f''
\ No newline at end of file
diff --git a/backend/modelo/reservas.py b/backend/modelo/reservas.py
new file mode 100644
index 00000000..3e48958e
--- /dev/null
+++ b/backend/modelo/reservas.py
@@ -0,0 +1,50 @@
+# TODO: ver quais dados ainda precisa colocar aqui
+import copy
+
+mock_reservas = [
+ {
+ "id": 1,
+ "professor_id": 3,
+ "sala_id": 5,
+ "data": "2025-02-20",
+ "start_time": "14:00",
+ "end_time": "15:00",
+ "status": "ativa"
+ },
+
+ {
+ "id": 2,
+ "professor_id": 3,
+ "sala_id": 3,
+ "data": "2025-02-21",
+ "start_time": "09:00",
+ "end_time": "11:00",
+ "status": "ativa"
+ },
+
+ {
+ "id": 3,
+ "professor_id": 3,
+ "sala_id": 1,
+ "data": "2025-02-22",
+ "start_time": "08:00",
+ "end_time": "10:00",
+ "status": "ativa"
+ },
+
+ {
+ "id": 4,
+ "professor_id": 3,
+ "sala_id": 2,
+ "data": "2025-02-20",
+ "start_time": "16:00",
+ "end_time": "18:00",
+ "status": "ativa"
+ }
+]
+
+MOCK_RESERVAS_COPY = copy.copy(mock_reservas)
+
+def reservas_reset():
+ mock_reservas.clear()
+ mock_reservas.extend(copy.copy(MOCK_RESERVAS_COPY))
\ No newline at end of file
diff --git a/backend/modelo/reviewSala.py b/backend/modelo/reviewSala.py
new file mode 100644
index 00000000..0bab0557
--- /dev/null
+++ b/backend/modelo/reviewSala.py
@@ -0,0 +1,21 @@
+from backend.modelo.extensao import db
+from backend.modelo.sala import Sala
+from backend.modelo.reserva import Reserva
+
+# Definindo a tabela de Avaliações de Salas (ReviewSala)
+class ReviewSala(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ reserva_id = db.Column(db.Integer, db.ForeignKey('reserva.id'), nullable=False)
+ sala_id = db.Column(db.Integer, db.ForeignKey('sala.id'), nullable=False)
+ usuario_id = db.Column(db.Integer, db.ForeignKey('Usuario.id'), nullable=False)
+ nota = db.Column(db.Integer, nullable=False)
+ comentario = db.Column(db.String(500))
+ data_avaliacao = db.Column(db.DateTime, default=db.func.now())
+
+ # Relacionamento
+ reserva = db.relationship('Reserva', backref=db.backref('reviews', lazy=True))
+ sala = db.relationship('Sala', backref=db.backref('reviews', lazy=True))
+ usuario = db.relationship('Usuario', backref=db.backref('reviews', lazy=True))
+
+ def __repr__(self):
+ return f''
diff --git a/backend/modelo/sala.py b/backend/modelo/sala.py
new file mode 100644
index 00000000..89065cc0
--- /dev/null
+++ b/backend/modelo/sala.py
@@ -0,0 +1,10 @@
+from backend.modelo.extensao import db
+
+# Definindo a tabela de Salas
+class Sala(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ nome = db.Column(db.String(100), nullable=False)
+ capacidade = db.Column(db.Integer)
+
+ def __repr__(self):
+ return f''
diff --git a/backend/modelo/salas.py b/backend/modelo/salas.py
new file mode 100644
index 00000000..4bff9860
--- /dev/null
+++ b/backend/modelo/salas.py
@@ -0,0 +1,97 @@
+import copy
+
+EQUIPAMENTOS = [
+ "Ar-condicionado", "Cabo P2", "Cabo HDMI", "Cabo VGA", "Microfone",
+ "Extensão", "Mesa de som", "Passador", "Televisor", "Projetor",
+ "Carregador", "Pen Drive", "Mouse", "Teclado", "Monitor", "USB-C",
+ "Cafeteira", "Gelágua"
+]
+
+mock_salas = [
+ {
+ "id": 1,
+ "nome": "E001",
+ "tipo": "Reunião",
+ "lugares": 14,
+ "andar": 15,
+ "equipamentos": ["Ar-condicionado", "Televisor"],
+ "average_rating": 4.0,
+ "review_count": 2
+ },
+ {
+ "id": 2,
+ "nome": "E002",
+ "tipo": "Auditório",
+ "lugares": 50,
+ "andar": 10,
+ "equipamentos": ["Projetor", "Microfone", "Mesa de som"],
+ "average_rating": 5.0,
+ "review_count": 5
+ },
+ {
+ "id": 3,
+ "nome": "E003",
+ "tipo": "Reunião",
+ "lugares": 8,
+ "andar": 7,
+ "equipamentos": ["Cabo HDMI", "Cabo VGA", "Extensão"],
+ "average_rating": 3.5,
+ "review_count": 3
+ },
+ {
+ "id": 4,
+ "nome": "E004",
+ "tipo": "Auditório",
+ "lugares": 80,
+ "andar": 5,
+ "equipamentos": ["Projetor", "Mesa de som", "Passador", "Teclado", "Mouse"],
+ "average_rating": 4.8,
+ "review_count": 10
+ },
+ {
+ "id": 5,
+ "nome": "E005",
+ "tipo": "Reunião",
+ "lugares": 12,
+ "andar": 9,
+ "equipamentos": ["Monitor", "USB-C", "Cabo P2"],
+ "average_rating": 4.2,
+ "review_count": 6
+ },
+ {
+ "id": 6,
+ "nome": "E006",
+ "tipo": "Reunião",
+ "lugares": 6,
+ "andar": 3,
+ "equipamentos": ["Ar-condicionado", "Gelágua", "Cafeteira"],
+ "average_rating": 3.9,
+ "review_count": 4
+ },
+ {
+ "id": 7,
+ "nome": "E007",
+ "tipo": "Auditório",
+ "lugares": 100,
+ "andar": 2,
+ "equipamentos": ["Projetor", "Microfone", "Mesa de som", "Extensão"],
+ "average_rating": 4.7,
+ "review_count": 8
+ },
+ {
+ "id": 8,
+ "nome": "E008",
+ "tipo": "Reunião",
+ "lugares": 10,
+ "andar": 4,
+ "equipamentos": ["Carregador", "Pen Drive", "USB-C"],
+ "average_rating": 4.5,
+ "review_count": 7
+ }
+]
+
+MOCK_SALAS_COPY = copy.copy(mock_salas)
+
+def salas_reset():
+ mock_salas.clear()
+ mock_salas.extend(copy.copy(MOCK_SALAS_COPY))
diff --git a/backend/modelo/solicitacaomanutencao.py b/backend/modelo/solicitacaomanutencao.py
new file mode 100644
index 00000000..ea49267e
--- /dev/null
+++ b/backend/modelo/solicitacaomanutencao.py
@@ -0,0 +1,7 @@
+from backend.modelo.extensao import db
+import datetime
+
+class SolicitacaoManutencao(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ reserva_id = db.Column(db.Integer, nullable=False)
+ descricao = db.Column(db.Text, nullable=False) # Descrição da manutenção
\ No newline at end of file
diff --git a/backend/modelo/solicitacaorecursos.py b/backend/modelo/solicitacaorecursos.py
new file mode 100644
index 00000000..7dc3b497
--- /dev/null
+++ b/backend/modelo/solicitacaorecursos.py
@@ -0,0 +1,9 @@
+from backend.modelo.extensao import db
+import datetime
+
+class SolicitacaoRecursos(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ reserva_id = db.Column(db.Integer, nullable=False) # Associa à reserva
+ recursos = db.Column(db.Text, nullable=False) # Itens solicitados
+ itens_nao_listados = db.Column(db.Text, nullable=True)
+ observacoes = db.Column(db.Text, nullable=True)
\ No newline at end of file
diff --git a/backend/modelo/usuario.py b/backend/modelo/usuario.py
new file mode 100644
index 00000000..c72958cc
--- /dev/null
+++ b/backend/modelo/usuario.py
@@ -0,0 +1,12 @@
+from backend.modelo.extensao import db
+
+# Modelo da Tabela de Usuários
+class Usuario(db.Model):
+ __tablename__ = "Usuario"
+ id = db.Column(db.Integer, primary_key=True)
+ nome = db.Column(db.String(100), nullable=False)
+ cpf = db.Column(db.String(14), unique=True, nullable=False)
+ email = db.Column(db.String(100), unique=True, nullable=False)
+ professor = db.Column(db.String(1), nullable=False) # "S" ou "N"
+ siape = db.Column(db.String(6), unique=True)
+ senha = db.Column(db.String(200), nullable=False)
\ No newline at end of file
diff --git a/backend/requirements.txt b/backend/requirements.txt
new file mode 100644
index 00000000..f86f6786
--- /dev/null
+++ b/backend/requirements.txt
@@ -0,0 +1,30 @@
+blinker==1.9.0
+certifi==2025.1.31
+charset-normalizer==3.4.1
+click==8.1.8
+colorama==0.4.6
+Flask==3.1.0
+Flask-Cors==5.0.0
+Flask-JWT-Extended==4.7.1
+Flask-SQLAlchemy==3.1.1
+gherkin-official==29.0.0
+greenlet==3.1.1
+idna==3.10
+iniconfig==2.0.0
+itsdangerous==2.2.0
+Jinja2==3.1.5
+Mako==1.3.9
+MarkupSafe==3.0.2
+packaging==24.2
+parse==1.20.2
+parse_type==0.6.4
+pluggy==1.5.0
+PyJWT==2.10.1
+pytest==8.3.4
+pytest-bdd==8.1.0
+requests==2.32.3
+six==1.17.0
+SQLAlchemy==2.0.38
+typing_extensions==4.12.2
+urllib3==2.3.0
+Werkzeug==3.1.3
diff --git a/backend/rotas/__init__.py b/backend/rotas/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/rotas/__pycache__/__init__.cpython-312.pyc b/backend/rotas/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 00000000..3f93da27
Binary files /dev/null and b/backend/rotas/__pycache__/__init__.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/__init__.cpython-313.pyc b/backend/rotas/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 00000000..8da29c37
Binary files /dev/null and b/backend/rotas/__pycache__/__init__.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/atualizarReview.cpython-313.pyc b/backend/rotas/__pycache__/atualizarReview.cpython-313.pyc
new file mode 100644
index 00000000..fdd0d7b0
Binary files /dev/null and b/backend/rotas/__pycache__/atualizarReview.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/cadastro.cpython-312.pyc b/backend/rotas/__pycache__/cadastro.cpython-312.pyc
new file mode 100644
index 00000000..d57b64f0
Binary files /dev/null and b/backend/rotas/__pycache__/cadastro.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/cadastro.cpython-313.pyc b/backend/rotas/__pycache__/cadastro.cpython-313.pyc
new file mode 100644
index 00000000..20f8eea7
Binary files /dev/null and b/backend/rotas/__pycache__/cadastro.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/criarReview.cpython-313.pyc b/backend/rotas/__pycache__/criarReview.cpython-313.pyc
new file mode 100644
index 00000000..860b34a4
Binary files /dev/null and b/backend/rotas/__pycache__/criarReview.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/criar_solicitacao_manutencao.cpython-312.pyc b/backend/rotas/__pycache__/criar_solicitacao_manutencao.cpython-312.pyc
new file mode 100644
index 00000000..e25435ad
Binary files /dev/null and b/backend/rotas/__pycache__/criar_solicitacao_manutencao.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/criar_solicitacao_manutencao.cpython-313.pyc b/backend/rotas/__pycache__/criar_solicitacao_manutencao.cpython-313.pyc
new file mode 100644
index 00000000..3572d21b
Binary files /dev/null and b/backend/rotas/__pycache__/criar_solicitacao_manutencao.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/criar_solicitacao_recursos.cpython-312.pyc b/backend/rotas/__pycache__/criar_solicitacao_recursos.cpython-312.pyc
new file mode 100644
index 00000000..6e7a1754
Binary files /dev/null and b/backend/rotas/__pycache__/criar_solicitacao_recursos.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/criar_solicitacao_recursos.cpython-313.pyc b/backend/rotas/__pycache__/criar_solicitacao_recursos.cpython-313.pyc
new file mode 100644
index 00000000..2bbd243b
Binary files /dev/null and b/backend/rotas/__pycache__/criar_solicitacao_recursos.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/deletarReview.cpython-313.pyc b/backend/rotas/__pycache__/deletarReview.cpython-313.pyc
new file mode 100644
index 00000000..c47dccbb
Binary files /dev/null and b/backend/rotas/__pycache__/deletarReview.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/editar_solicitacao_manutencao.cpython-312.pyc b/backend/rotas/__pycache__/editar_solicitacao_manutencao.cpython-312.pyc
new file mode 100644
index 00000000..e22af9e3
Binary files /dev/null and b/backend/rotas/__pycache__/editar_solicitacao_manutencao.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/editar_solicitacao_manutencao.cpython-313.pyc b/backend/rotas/__pycache__/editar_solicitacao_manutencao.cpython-313.pyc
new file mode 100644
index 00000000..70546294
Binary files /dev/null and b/backend/rotas/__pycache__/editar_solicitacao_manutencao.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/editar_solicitacao_recursos.cpython-312.pyc b/backend/rotas/__pycache__/editar_solicitacao_recursos.cpython-312.pyc
new file mode 100644
index 00000000..38649e7d
Binary files /dev/null and b/backend/rotas/__pycache__/editar_solicitacao_recursos.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/editar_solicitacao_recursos.cpython-313.pyc b/backend/rotas/__pycache__/editar_solicitacao_recursos.cpython-313.pyc
new file mode 100644
index 00000000..4c4f63cb
Binary files /dev/null and b/backend/rotas/__pycache__/editar_solicitacao_recursos.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/excluir_solicitacao_manutencao.cpython-312.pyc b/backend/rotas/__pycache__/excluir_solicitacao_manutencao.cpython-312.pyc
new file mode 100644
index 00000000..a3e25b9f
Binary files /dev/null and b/backend/rotas/__pycache__/excluir_solicitacao_manutencao.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/excluir_solicitacao_manutencao.cpython-313.pyc b/backend/rotas/__pycache__/excluir_solicitacao_manutencao.cpython-313.pyc
new file mode 100644
index 00000000..82516e15
Binary files /dev/null and b/backend/rotas/__pycache__/excluir_solicitacao_manutencao.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/excluir_solicitacao_recursos.cpython-312.pyc b/backend/rotas/__pycache__/excluir_solicitacao_recursos.cpython-312.pyc
new file mode 100644
index 00000000..22bb541b
Binary files /dev/null and b/backend/rotas/__pycache__/excluir_solicitacao_recursos.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/excluir_solicitacao_recursos.cpython-313.pyc b/backend/rotas/__pycache__/excluir_solicitacao_recursos.cpython-313.pyc
new file mode 100644
index 00000000..c8a04a42
Binary files /dev/null and b/backend/rotas/__pycache__/excluir_solicitacao_recursos.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/listarReview.cpython-313.pyc b/backend/rotas/__pycache__/listarReview.cpython-313.pyc
new file mode 100644
index 00000000..8de930d4
Binary files /dev/null and b/backend/rotas/__pycache__/listarReview.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/login.cpython-312.pyc b/backend/rotas/__pycache__/login.cpython-312.pyc
new file mode 100644
index 00000000..05b489cf
Binary files /dev/null and b/backend/rotas/__pycache__/login.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/login.cpython-313.pyc b/backend/rotas/__pycache__/login.cpython-313.pyc
new file mode 100644
index 00000000..eb2a98d4
Binary files /dev/null and b/backend/rotas/__pycache__/login.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/logout.cpython-312.pyc b/backend/rotas/__pycache__/logout.cpython-312.pyc
new file mode 100644
index 00000000..6f29e6e6
Binary files /dev/null and b/backend/rotas/__pycache__/logout.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/logout.cpython-313.pyc b/backend/rotas/__pycache__/logout.cpython-313.pyc
new file mode 100644
index 00000000..686eadcf
Binary files /dev/null and b/backend/rotas/__pycache__/logout.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/obterReview.cpython-313.pyc b/backend/rotas/__pycache__/obterReview.cpython-313.pyc
new file mode 100644
index 00000000..d1217c8c
Binary files /dev/null and b/backend/rotas/__pycache__/obterReview.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/reservas.cpython-313.pyc b/backend/rotas/__pycache__/reservas.cpython-313.pyc
new file mode 100644
index 00000000..c048c172
Binary files /dev/null and b/backend/rotas/__pycache__/reservas.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/salas.cpython-313.pyc b/backend/rotas/__pycache__/salas.cpython-313.pyc
new file mode 100644
index 00000000..88302b42
Binary files /dev/null and b/backend/rotas/__pycache__/salas.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/testecookies.cpython-312.pyc b/backend/rotas/__pycache__/testecookies.cpython-312.pyc
new file mode 100644
index 00000000..693c4203
Binary files /dev/null and b/backend/rotas/__pycache__/testecookies.cpython-312.pyc differ
diff --git a/backend/rotas/__pycache__/testecookies.cpython-313.pyc b/backend/rotas/__pycache__/testecookies.cpython-313.pyc
new file mode 100644
index 00000000..356508dd
Binary files /dev/null and b/backend/rotas/__pycache__/testecookies.cpython-313.pyc differ
diff --git a/backend/rotas/__pycache__/usuario.cpython-313.pyc b/backend/rotas/__pycache__/usuario.cpython-313.pyc
new file mode 100644
index 00000000..0c35f83b
Binary files /dev/null and b/backend/rotas/__pycache__/usuario.cpython-313.pyc differ
diff --git a/backend/rotas/atualizarReview.py b/backend/rotas/atualizarReview.py
new file mode 100644
index 00000000..45424b30
--- /dev/null
+++ b/backend/rotas/atualizarReview.py
@@ -0,0 +1,20 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.reviewSala import ReviewSala
+
+atualizar_review_bp = Blueprint("atualizar_review", __name__)
+
+@atualizar_review_bp.route("/api/reviews/", methods=["PUT"])
+def atualizar_review(id):
+ review = db.session.get(ReviewSala, id)
+ #Verifica o ID
+ if not review:
+ return jsonify({"error": "Avaliação não encontrada para o ID fornecido."}), 404
+
+ data = request.get_json()
+ # Atualiza a nota e o comentário se estiverem presentes no JSON
+ review.nota = data.get("nota", review.nota)
+ review.comentario = data.get("comentario", review.comentario)
+
+ db.session.commit()
+ return jsonify({"mensagem": "Avaliação atualizada com sucesso!"})
diff --git a/backend/rotas/cadastro.py b/backend/rotas/cadastro.py
new file mode 100644
index 00000000..f3b0721d
--- /dev/null
+++ b/backend/rotas/cadastro.py
@@ -0,0 +1,79 @@
+from flask import Blueprint, request, jsonify
+from werkzeug.security import generate_password_hash
+from backend.modelo.usuario import Usuario
+from backend.modelo.extensao import db
+import re
+from sqlalchemy import exists
+
+cadastro_bp = Blueprint("cadastro", __name__)
+
+def validarEmail(email):
+ """Valida o formato do email."""
+ padraoEmail = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
+ return bool(re.match(padraoEmail, email))
+
+def validarCpf(cpf):
+ """Valida se o CPF está no formato correto XXX.XXX.XXX-XX"""
+ padraoCpf = r'^\d{3}\.\d{3}\.\d{3}-\d{2}$'
+ return bool(re.match(padraoCpf, cpf))
+
+@cadastro_bp.route("/cadastro", methods=["POST"])
+def cadastro():
+ data = request.get_json()
+
+ nome = data.get("nome", "").strip()
+ cpf = data.get("cpf", "").strip()
+ email = data.get("email", "").lower().strip()
+ professor = data.get("professor", "").upper().strip()
+ siape = data.get("siape", "").strip() if professor == "S" else None
+ senha = data.get("senha", "").strip()
+ confirmar_senha = data.get("confirmarSenha", "").strip()
+
+ camposObrigatorios = {
+ "nome": nome,
+ "cpf": cpf,
+ "email": email,
+ "senha": senha,
+ "Confirmar Senha": confirmar_senha
+ }
+ if professor == "S":
+ camposObrigatorios["siape"] = siape
+
+ for campo, valor in camposObrigatorios.items():
+ if not valor:
+ return jsonify({"error": f"{campo} é obrigatório."}), 400
+
+ if not validarEmail(email):
+ return jsonify({"error": "Formato de email inválido. Use um email válido, como exemplo@dominio.com."}), 400
+
+ if not validarCpf(cpf):
+ return jsonify({"error": "CPF inválido. Digite um CPF válido no formato XXX.XXX.XXX-XX."}), 400
+
+ usuarioExistente = db.session.query(
+ exists().where((Usuario.email == email) | (Usuario.cpf == cpf))
+ ).scalar()
+
+ if usuarioExistente:
+ return jsonify({"error": "Erro: email/cpf já está registrado."}), 409
+
+ if professor == "S":
+ siapeExistente = db.session.query(
+ exists().where(Usuario.siape == siape)
+ ).scalar()
+
+ if siapeExistente:
+ return jsonify({"error": "Erro: siape já está registrado."}), 409
+
+ if senha != confirmar_senha:
+ return jsonify({"error": "As senhas não coincidem."}), 400
+
+ senhaHash = generate_password_hash(senha)
+
+ novoUsuario = Usuario(
+ nome=nome, cpf=cpf, email=email, professor=professor, siape=siape, senha=senhaHash
+ )
+
+ db.session.add(novoUsuario)
+ db.session.commit()
+
+ return jsonify({"message": "Cadastro criado com sucesso!"}), 201
diff --git a/backend/rotas/criarReview.py b/backend/rotas/criarReview.py
new file mode 100644
index 00000000..6404d2b6
--- /dev/null
+++ b/backend/rotas/criarReview.py
@@ -0,0 +1,36 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.reviewSala import ReviewSala
+
+criar_review_bp = Blueprint("criar_review", __name__)
+
+@criar_review_bp.route("/api/reviews", methods=["POST"])
+def criar_review():
+ data = request.get_json()
+
+ # Aqui tá verificando se os campos obrigatórios foram preenchidos
+ # se faltar o comentário, ainda vai passar (campo não obrigatório)
+
+ if data.get("nota") is None:
+ return jsonify({"error": "A nota é obrigatória para avaliar a sala."}), 400
+
+ elif data.get("sala_id") is None:
+ return jsonify({"error": "O ID da Sala é obrigatório para avaliar a sala."}), 400
+
+ elif data.get("usuario_id") is None:
+ return jsonify({"error": "O ID do Usuário é obrigatório para avaliar a sala."}), 400
+
+ elif data.get("reserva_id") is None:
+ return jsonify({"error": "O ID da Reserva é obrigatório para avaliar a sala."}), 400
+
+ # Verifica tudo e prossegue pra avaliação!
+ nova_review = ReviewSala(
+ reserva_id=data.get("reserva_id"),
+ sala_id=data.get("sala_id"),
+ usuario_id=data.get("usuario_id"),
+ nota=data.get("nota"),
+ comentario=data.get("comentario")
+ )
+ db.session.add(nova_review)
+ db.session.commit()
+ return jsonify({"mensagem": "Avaliação criada com sucesso!"}), 201
diff --git a/backend/rotas/criar_solicitacao_manutencao.py b/backend/rotas/criar_solicitacao_manutencao.py
new file mode 100644
index 00000000..71ca786c
--- /dev/null
+++ b/backend/rotas/criar_solicitacao_manutencao.py
@@ -0,0 +1,22 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.solicitacaomanutencao import SolicitacaoManutencao
+from backend.modelo.solicitacaorecursos import SolicitacaoRecursos
+
+criar_manutencao_bp = Blueprint("criarmanutencao", __name__)
+
+@criar_manutencao_bp.route("/solicitacoes/manutencao", methods=["POST"])
+def criar_solicitacao_manutencao():
+ dados = request.json
+
+ # Verifica se 'descricao' está vazio ou None
+ if not dados.get("descricao").strip():
+ return jsonify({"erro": "O campo 'descricao' não pode estar vazio."}), 400
+
+ solicitacao = SolicitacaoManutencao(
+ reserva_id=dados.get("reserva_id"),
+ descricao=dados.get("descricao")
+ )
+ db.session.add(solicitacao)
+ db.session.commit()
+ return jsonify({"id": solicitacao.id, "mensagem": "Parabéns, sua solicitação de manutenção foi criada!"}), 201
\ No newline at end of file
diff --git a/backend/rotas/criar_solicitacao_recursos.py b/backend/rotas/criar_solicitacao_recursos.py
new file mode 100644
index 00000000..6d4e74e3
--- /dev/null
+++ b/backend/rotas/criar_solicitacao_recursos.py
@@ -0,0 +1,38 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.solicitacaomanutencao import SolicitacaoManutencao
+from backend.modelo.solicitacaorecursos import SolicitacaoRecursos
+
+criar_recursos_bp = Blueprint("criarrecursos", __name__)
+
+@criar_recursos_bp.route("/solicitacoes/recursos", methods=["POST"])
+def criar_solicitacao_recursos():
+ dados = request.json
+
+ recursos = dados.get("recursos", "").strip()
+ itens_nao_listados = dados.get("itens_nao_listados", "").strip()
+
+ # Validação: se recursos estiver vazio, itens_nao_listados deve estar preenchido
+ if not recursos and not itens_nao_listados:
+ return jsonify({"erro": "Você deve selecionar um recurso ou especificar itens não listados."}), 400
+
+ # Verifica se 'recursos' é None ou uma string vazia
+ #if not dados.get("recursos"):
+ #return jsonify({"error": "O campo 'recursos' não pode estar vazio."}), 400
+
+ #solicitacao = SolicitacaoRecursos(
+ #reserva_id=dados.get("reserva_id"),
+ #recursos=dados.get("recursos"),
+ #itens_nao_listados=dados.get("itens_nao_listados"),
+ #observacoes=dados.get("observacoes")
+ #)
+
+ solicitacao = SolicitacaoRecursos(
+ reserva_id=dados.get("reserva_id"),
+ recursos=recursos,
+ itens_nao_listados=itens_nao_listados,
+ observacoes=dados.get("observacoes", "").strip()
+ )
+ db.session.add(solicitacao)
+ db.session.commit()
+ return jsonify({"id": solicitacao.id, "mensagem": "Parabéns, sua solicitação de recursos foi criada!"}), 201
\ No newline at end of file
diff --git a/backend/rotas/deletarReview.py b/backend/rotas/deletarReview.py
new file mode 100644
index 00000000..505ca3af
--- /dev/null
+++ b/backend/rotas/deletarReview.py
@@ -0,0 +1,16 @@
+from flask import Blueprint, jsonify, abort
+from backend.modelo.extensao import db
+from backend.modelo.reviewSala import ReviewSala
+
+deletar_review_bp = Blueprint("deletar_review", __name__)
+
+@deletar_review_bp.route("/api/reviews/", methods=["DELETE"])
+def deletar_review(id):
+ review = db.session.get(ReviewSala, id)
+ #Verifica o ID
+ if not review:
+ return jsonify({"error": "Avaliação não encontrada para o ID fornecido."}), 404
+
+ db.session.delete(review)
+ db.session.commit()
+ return jsonify({"mensagem": "Avaliação deletada com sucesso!"})
diff --git a/backend/rotas/editar_solicitacao_manutencao.py b/backend/rotas/editar_solicitacao_manutencao.py
new file mode 100644
index 00000000..8412ab8f
--- /dev/null
+++ b/backend/rotas/editar_solicitacao_manutencao.py
@@ -0,0 +1,27 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.solicitacaomanutencao import SolicitacaoManutencao
+from backend.modelo.solicitacaorecursos import SolicitacaoRecursos
+import flask
+
+editar_manutencao_bp = Blueprint("editarmanutencao", __name__)
+
+@editar_manutencao_bp.route("/solicitacoes/manutencao/", methods=["PUT"])
+def editar_solicitacao_manutencao(id):
+ solicitacao = db.session.get(SolicitacaoManutencao, id) or flask.abort(404)
+
+ dados = request.json
+
+ # Verifica se a nova descrição é vazia ou apenas espaços em branco
+ nova_descricao = dados.get("descricao", solicitacao.descricao)
+ if not nova_descricao.strip():
+ return jsonify({"erro": "A descrição da manutenção não pode ser vazia"}), 400
+
+ solicitacao.descricao = nova_descricao
+ db.session.commit()
+ return jsonify({
+ "mensagem": "Solicitação de manutenção atualizada com sucesso",
+ "id": solicitacao.id,
+ #"reserva_id": solicitacao.reserva_id,
+ "descricao": solicitacao.descricao
+}), 200
\ No newline at end of file
diff --git a/backend/rotas/editar_solicitacao_recursos.py b/backend/rotas/editar_solicitacao_recursos.py
new file mode 100644
index 00000000..16ad8223
--- /dev/null
+++ b/backend/rotas/editar_solicitacao_recursos.py
@@ -0,0 +1,27 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.solicitacaomanutencao import SolicitacaoManutencao
+from backend.modelo.solicitacaorecursos import SolicitacaoRecursos
+import flask
+
+editar_recursos_bp = Blueprint("editarrecursos", __name__)
+
+@editar_recursos_bp.route("/solicitacoes/recursos/", methods=["PUT"])
+def editar_solicitacao_recursos(id):
+ solicitacao = db.session.get(SolicitacaoRecursos, id) or flask.abort(404)
+ dados = request.json
+
+ # Verifica se ambos os campos estão vazios
+ recursos = dados.get("recursos", "").strip()
+ itens_nao_listados = dados.get("itens_nao_listados", "").strip()
+
+ if not recursos and not itens_nao_listados:
+ return jsonify({"erro": "Você deve preencher pelo menos 'recursos' ou 'itens_nao_listados'."}), 400
+
+ # Atualiza os campos apenas se foram passados na requisição
+ solicitacao.recursos = recursos if "recursos" in dados else solicitacao.recursos
+ solicitacao.itens_nao_listados = itens_nao_listados if "itens_nao_listados" in dados else solicitacao.itens_nao_listados
+ solicitacao.observacoes = dados.get("observacoes", solicitacao.observacoes)
+
+ db.session.commit()
+ return jsonify({"mensagem": "Solicitação de recursos atualizada com sucesso"}), 200
\ No newline at end of file
diff --git a/backend/rotas/excluir_solicitacao_manutencao.py b/backend/rotas/excluir_solicitacao_manutencao.py
new file mode 100644
index 00000000..39855f6b
--- /dev/null
+++ b/backend/rotas/excluir_solicitacao_manutencao.py
@@ -0,0 +1,15 @@
+from flask import Blueprint, request, jsonify
+import flask
+from backend.modelo.extensao import db
+from backend.modelo.solicitacaomanutencao import SolicitacaoManutencao
+from backend.modelo.solicitacaorecursos import SolicitacaoRecursos
+
+excluir_manutencao_bp = Blueprint("excluirmanutencao", __name__)
+
+@excluir_manutencao_bp.route("/solicitacoes/manutencao/", methods=["DELETE"])
+def excluir_solicitacao_manutencao(id):
+ solicitacao = db.session.get(SolicitacaoManutencao, id) or flask.abort(404)
+
+ db.session.delete(solicitacao)
+ db.session.commit()
+ return jsonify({"message": "Solicitação excluída"}), 204
diff --git a/backend/rotas/excluir_solicitacao_recursos.py b/backend/rotas/excluir_solicitacao_recursos.py
new file mode 100644
index 00000000..bcb2664d
--- /dev/null
+++ b/backend/rotas/excluir_solicitacao_recursos.py
@@ -0,0 +1,14 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.solicitacaomanutencao import SolicitacaoManutencao
+from backend.modelo.solicitacaorecursos import SolicitacaoRecursos
+import flask
+
+excluir_recursos_bp = Blueprint("excluirrecursos", __name__)
+
+@excluir_recursos_bp.route("/solicitacoes/recursos/", methods=["DELETE"])
+def excluir_solicitacao_recursos(id):
+ solicitacao = db.session.get(SolicitacaoRecursos, id) or flask.abort(404)
+ db.session.delete(solicitacao)
+ db.session.commit()
+ return jsonify({"message": "Solicitação excluída"}), 204
diff --git a/backend/rotas/listarReview.py b/backend/rotas/listarReview.py
new file mode 100644
index 00000000..352046f2
--- /dev/null
+++ b/backend/rotas/listarReview.py
@@ -0,0 +1,24 @@
+from flask import Blueprint, jsonify
+from backend.modelo.reviewSala import ReviewSala
+
+listar_reviews_bp = Blueprint("listar_reviews", __name__)
+
+@listar_reviews_bp.route("/api/reviews", methods=["GET"])
+def listar_reviews():
+ reviews = ReviewSala.query.all()
+ #Verifica as avaliações
+ if not reviews:
+ return jsonify({"error": "Nenhuma avaliação encontrada."}), 404
+
+ resultado = []
+ for review in reviews:
+ resultado.append({
+ "id": review.id,
+ "reserva_id": review.reserva_id,
+ "sala_id": review.sala_id,
+ "usuario_id": review.usuario_id,
+ "nota": review.nota,
+ "comentario": review.comentario,
+ "data_avaliacao": review.data_avaliacao
+ })
+ return jsonify(resultado), 200
diff --git a/backend/rotas/login.py b/backend/rotas/login.py
new file mode 100644
index 00000000..bf5dbaed
--- /dev/null
+++ b/backend/rotas/login.py
@@ -0,0 +1,31 @@
+from flask import Blueprint, jsonify, request, make_response
+from backend.modelo.usuario import Usuario
+from werkzeug.security import check_password_hash
+
+login_bp = Blueprint("login", __name__)
+
+@login_bp.route("/", methods=["POST"])
+def login():
+ data = request.get_json()
+
+ print("Dados recebidos no login:", data)
+
+ # Pegando os valores com `.get()` para evitar erro caso estejam ausentes
+ email = data.get("email", "").strip()
+ senha = data.get("senha", "").strip()
+
+ if not email or not senha:
+ return jsonify({"success": False, "error": "Usuário e senha são obrigatórios."}), 400
+
+ # Buscar usuário no banco
+ usuario = Usuario.query.filter_by(email=email).first()
+ if not usuario or not check_password_hash(usuario.senha, senha):
+ return jsonify({"success": False, "error": "Usuário ou senha inválidos."}), 401
+
+ return jsonify({
+ "success": True,
+ "usuario": {
+ "email": usuario.email
+ }
+
+ }), 200
\ No newline at end of file
diff --git a/backend/rotas/logout.py b/backend/rotas/logout.py
new file mode 100644
index 00000000..f9d69aaa
--- /dev/null
+++ b/backend/rotas/logout.py
@@ -0,0 +1,8 @@
+from flask import Blueprint, jsonify
+
+logout_bp = Blueprint("logout", __name__)
+
+@logout_bp.route("/api/logout", methods=["POST"])
+def logout():
+ response = jsonify({"message": "Logout realizado com sucesso."})
+ return response, 200
diff --git a/backend/rotas/obterReview.py b/backend/rotas/obterReview.py
new file mode 100644
index 00000000..8780d83b
--- /dev/null
+++ b/backend/rotas/obterReview.py
@@ -0,0 +1,22 @@
+from flask import Blueprint, jsonify
+from backend.modelo.reviewSala import ReviewSala
+from backend.modelo.extensao import db
+
+obter_review_bp = Blueprint("obter_review", __name__)
+
+@obter_review_bp.route("/api/reviews/", methods=["GET"])
+def obter_review(id):
+ review = db.session.get(ReviewSala, id)
+ #Verifica o ID
+ if not review:
+ return jsonify({"error": "Avaliação não encontrada para o ID fornecido."}), 404
+
+ return jsonify({
+ "id": review.id,
+ "reserva_id": review.reserva_id,
+ "sala_id": review.sala_id,
+ "usuario_id": review.usuario_id,
+ "nota": review.nota,
+ "comentario": review.comentario,
+ "data_avaliacao": review.data_avaliacao
+ })
diff --git a/backend/rotas/reservas.py b/backend/rotas/reservas.py
new file mode 100644
index 00000000..1328de2c
--- /dev/null
+++ b/backend/rotas/reservas.py
@@ -0,0 +1,93 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.reservas import mock_reservas
+from datetime import datetime
+
+reservas_bp = Blueprint('reservas', __name__)
+
+def parse_time(time_str):
+ return datetime.strptime(time_str, "%H:%M").time()
+
+# Get reservas
+@reservas_bp.route('/api/reservas', methods=['GET'])
+def get_reservas():
+ return jsonify(mock_reservas), 200
+
+# Get reservas para um usuário
+@reservas_bp.route('/api/reservas/', methods=['GET'])
+def get_reservas_professor(professor_id):
+ user_reservas = [
+ reserva for reserva in mock_reservas if reserva['professor_id'] == professor_id
+ ]
+
+ if not user_reservas:
+ return jsonify({'mensagem': 'Nenhuma reserva encontrada'}), 404
+
+ return jsonify(user_reservas), 200
+
+# Create reserva
+@reservas_bp.route('/api/reservas/', methods=['POST'])
+def create_reserva(professor_id):
+ """
+ Exemplo de body
+ {
+ "sala_id": 3,
+ "data": "2025-02-25",
+ "start_time": "14:00",
+ "end_time": "15:00"
+ }
+ """
+
+ dados = request.get_json()
+ sala_id = dados.get('sala_id')
+ data = dados.get('data')
+ start_time = dados.get('start_time')
+ end_time = dados.get('end_time')
+ status = "ativa"
+
+ # Checa se o body inclui o que precisa
+ if not sala_id or not data or not start_time or not end_time:
+ return jsonify({"erro": "Campos obrigatórios ausentes"}), 400
+
+ parsed_start_time = parse_time(start_time)
+ parsed_end_time = parse_time(end_time)
+
+ for reserva in mock_reservas:
+ if reserva['sala_id'] == sala_id and reserva['data'] == data and reserva['status'] == 'ativa':
+ reserva_start = parse_time(reserva['start_time'])
+ reserva_end = parse_time(reserva['end_time'])
+
+ # Sobreposição de horários
+ if not (reserva_end <= parsed_start_time or reserva_start >= parsed_end_time):
+ return jsonify({'erro': 'Sala já reservada para esse horário'}), 409
+
+ for reserva in mock_reservas:
+ if reserva['professor_id'] == professor_id and reserva['data'] == data and reserva['status'] == 'ativa':
+ professor_reserva_start = parse_time(reserva["start_time"])
+ professor_reserva_end = parse_time(reserva["end_time"])
+
+ if not (professor_reserva_end <= parsed_start_time or professor_reserva_start >= parsed_end_time):
+ return jsonify({"erro": "Professor já possui uma reserva nesse horário"}), 409
+
+ new_reserva = {
+ "id": len(mock_reservas) + 1,
+ "sala_id": sala_id,
+ "professor_id": professor_id,
+ "data": data,
+ "start_time": start_time,
+ "end_time": end_time,
+ "status": status
+ }
+ mock_reservas.append(new_reserva)
+
+ return jsonify({"mensagem": "Reserva criada com sucesso!", "reservation": new_reserva}), 201
+
+
+# Cancela reserva
+@reservas_bp.route('/api/reservas/', methods=['DELETE'])
+def cancel_reserva(reserva_id):
+ for reserva in mock_reservas:
+ if reserva['id'] == reserva_id:
+ reserva['status'] = 'cancelada'
+ return jsonify({"mensagem": "Reserva cancelada!", "reservation": reserva}), 200
+
+ return jsonify({"erro": "Reserva não encontrada."}), 404
\ No newline at end of file
diff --git a/backend/rotas/salas.py b/backend/rotas/salas.py
new file mode 100644
index 00000000..d3c32463
--- /dev/null
+++ b/backend/rotas/salas.py
@@ -0,0 +1,120 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.reservas import mock_reservas
+from backend.modelo.salas import mock_salas, EQUIPAMENTOS
+from datetime import datetime
+
+salas_bp = Blueprint('salas', __name__)
+
+# Convert "HH:MM" string to datetime.time
+def parse_time(time_str):
+ return datetime.strptime(time_str, "%H:%M").time()
+
+# Criar sala
+@salas_bp.route('/api/salas', methods=['POST'])
+def create_sala():
+ """
+ Exemplo de body:
+ {
+ "nome": "Sala E003",
+ "tipo": "Reunião",
+ "lugares": 20,
+ "andar": 3,
+ "equipamentos": ["Projetor", "Ar-condicionado"]
+ }
+ """
+
+ dados = request.get_json()
+
+ nome = dados.get("nome")
+ tipo = dados.get("tipo")
+ lugares = dados.get("lugares")
+ andar = dados.get("andar")
+ equipamentos = dados.get("equipamentos", [])
+
+
+ if not nome or not tipo or not lugares or not andar:
+ return jsonify({"erro": "Campos obrigatórios ausentes"}), 400
+
+ if tipo not in ["Reunião", "Auditório"]:
+ return jsonify({"erro": "Tipo de sala inválido. Escolha entre 'Reunião' ou 'Auditório'"}), 400
+
+ equipamentos_invalidos = [eq for eq in equipamentos if eq not in EQUIPAMENTOS]
+ if equipamentos_invalidos:
+ return jsonify({"erro": f"Equipamentos inválidos: {equipamentos_invalidos}"}), 400
+
+ if any(sala["nome"] == nome for sala in mock_salas):
+ return jsonify({"erro": "Já existe uma sala com esse nome"}), 409
+
+ nova_sala = {
+ "id": len(mock_salas) + 1,
+ "nome": nome,
+ "tipo": tipo,
+ "lugares": lugares,
+ "andar": andar,
+ "equipamentos": equipamentos
+ }
+ mock_salas.append(nova_sala)
+
+ return jsonify({"mensagem": "Sala criada com sucesso!", "sala": nova_sala}), 201
+
+
+# Get salas
+@salas_bp.route('/api/salas', methods=['GET'])
+def get_salas_disponiveis():
+ equipamentos_filtro = request.args.getlist("equipamentos") # Get filter from query params
+ data = request.args.get("data")
+ start_time = request.args.get("start_time")
+ end_time = request.args.get("end_time")
+
+ if not equipamentos_filtro and not data and not start_time and not end_time:
+ return jsonify(mock_salas), 200
+ elif not data:
+ return jsonify({'erro': 'data não informada'}), 400
+ elif not start_time or not end_time:
+ return jsonify({'erro': 'tempo não informado'}), 400
+
+
+ salas_filtradas = [
+ sala for sala in mock_salas
+ if not equipamentos_filtro or all(eq in sala["equipamentos"] for eq in equipamentos_filtro)
+ ]
+
+ if data and start_time and end_time:
+ salas_disponiveis = []
+ for sala in salas_filtradas:
+ reservas_existentes = [
+ reserva for reserva in mock_reservas
+ if reserva["sala_id"] == sala["id"] and reserva["data"] == data and
+ not (parse_time(reserva["end_time"]) <= parse_time(start_time) or
+ parse_time(reserva["start_time"]) >= parse_time(end_time)) and
+ reserva["status"] == "ativa"
+ ]
+
+ if not reservas_existentes:
+ salas_disponiveis.append(sala)
+ else:
+ salas_disponiveis = salas_filtradas
+
+ if not salas_disponiveis:
+ return jsonify({'mensagem': 'nenhuma sala encontrada'}), 404
+
+ return jsonify(salas_disponiveis), 200
+
+@salas_bp.route('/api/salas/', methods=['DELETE'])
+def delete_sala(sala_id):
+
+ sala = next((s for s in mock_salas if s["id"] == sala_id), None)
+ if not sala:
+ return jsonify({"erro": "Sala não encontrada"}), 404
+
+ reservas_ativas = [
+ reserva for reserva in mock_reservas
+ if reserva["sala_id"] == sala_id and reserva["status"] == "ativa"
+ ]
+
+ if reservas_ativas:
+ return jsonify({"erro": "Sala possui reservas ativas e não pode ser deletada"}), 409
+
+ mock_salas.remove(sala)
+
+ return jsonify({"mensagem": "Sala deletada com sucesso!"}), 200
\ No newline at end of file
diff --git a/backend/rotas/usuario.py b/backend/rotas/usuario.py
new file mode 100644
index 00000000..5ea30501
--- /dev/null
+++ b/backend/rotas/usuario.py
@@ -0,0 +1,35 @@
+from flask import Blueprint, request, jsonify
+from backend.modelo.extensao import db
+from backend.modelo.usuario import Usuario
+
+usuarios_bp = Blueprint('usuarios', __name__)
+
+@usuarios_bp.route('/api/usuarios', methods=['GET'])
+def get_usuarios():
+ usuarios = Usuario.query.all()
+
+ usuarios_json = [
+ {
+ "id": usuario.id,
+ "nome": usuario.nome,
+ "cpf": usuario.cpf,
+ "email": usuario.email,
+ "professor": usuario.professor
+ }
+ for usuario in usuarios
+ ]
+
+ return jsonify(usuarios_json), 200
+
+
+@usuarios_bp.route("/api/usuarios/", methods=["DELETE"])
+def deletar_usuario(usuario_id):
+ usuario = Usuario.query.get(usuario_id)
+
+ if not usuario:
+ return jsonify({"erro": "Usuário não encontrado"}), 404
+
+ db.session.delete(usuario)
+ db.session.commit()
+
+ return jsonify({"menssagem": "Usuário deletado com sucesso"}), 200
\ No newline at end of file
diff --git a/backend/testes/__init__.py b/backend/testes/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/backend/testes/__pycache__/__init__.cpython-313.pyc b/backend/testes/__pycache__/__init__.cpython-313.pyc
new file mode 100644
index 00000000..9085eede
Binary files /dev/null and b/backend/testes/__pycache__/__init__.cpython-313.pyc differ
diff --git a/backend/testes/__pycache__/common_step_definitions.cpython-313.pyc b/backend/testes/__pycache__/common_step_definitions.cpython-313.pyc
new file mode 100644
index 00000000..f6cd8101
Binary files /dev/null and b/backend/testes/__pycache__/common_step_definitions.cpython-313.pyc differ
diff --git a/backend/testes/__pycache__/conftest.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/conftest.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..5c901c0d
Binary files /dev/null and b/backend/testes/__pycache__/conftest.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_atualizarReview.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_atualizarReview.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..f1dc6684
Binary files /dev/null and b/backend/testes/__pycache__/test_atualizarReview.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_cadastro_servicos.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_cadastro_servicos.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..9006a689
Binary files /dev/null and b/backend/testes/__pycache__/test_cadastro_servicos.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_criarReview.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_criarReview.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..60ec2ea7
Binary files /dev/null and b/backend/testes/__pycache__/test_criarReview.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_deletarReview.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_deletarReview.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..20ff0de8
Binary files /dev/null and b/backend/testes/__pycache__/test_deletarReview.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_listarReview.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_listarReview.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..04a4bad1
Binary files /dev/null and b/backend/testes/__pycache__/test_listarReview.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_login_servicos.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_login_servicos.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..d200ab1a
Binary files /dev/null and b/backend/testes/__pycache__/test_login_servicos.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_manutencao.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_manutencao.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..2b4fbd80
Binary files /dev/null and b/backend/testes/__pycache__/test_manutencao.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_obterReview.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_obterReview.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..87f97504
Binary files /dev/null and b/backend/testes/__pycache__/test_obterReview.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_recursos.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_recursos.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..28e54f0a
Binary files /dev/null and b/backend/testes/__pycache__/test_recursos.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_reservas.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_reservas.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..f3fcb1d7
Binary files /dev/null and b/backend/testes/__pycache__/test_reservas.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/__pycache__/test_salas.cpython-313-pytest-8.3.4.pyc b/backend/testes/__pycache__/test_salas.cpython-313-pytest-8.3.4.pyc
new file mode 100644
index 00000000..ff33adde
Binary files /dev/null and b/backend/testes/__pycache__/test_salas.cpython-313-pytest-8.3.4.pyc differ
diff --git a/backend/testes/common_step_definitions.py b/backend/testes/common_step_definitions.py
new file mode 100644
index 00000000..a2ced8ee
--- /dev/null
+++ b/backend/testes/common_step_definitions.py
@@ -0,0 +1,65 @@
+import json
+import requests
+from pytest_bdd import when, then, given, parsers
+
+
+BASE_URL = 'http://127.0.0.1:5000'
+
+@when(parsers.parse('uma requisição "{metodo}" for enviada para "{url}" com o corpo: "{body}"'))
+def mandar_requisicao(metodo, url, body):
+ url = f'{BASE_URL}/{url}'
+
+ metodo = metodo.upper()
+ request_method = {
+ "POST": requests.post,
+ "GET": requests.get,
+ "DELETE": requests.delete,
+ "PUT": requests.put
+ }.get(metodo)
+
+ assert request_method is not None, f"Método HTTP inválido: {metodo}"
+
+ json_body = json.loads(body) if metodo in ["POST", "PUT"] else None
+
+ response = request_method(url, json=json_body)
+
+ mandar_requisicao.response = response
+
+
+@then(parsers.parse('o status da resposta deve ser "{status}"'))
+def checar_status(status):
+ assert mandar_requisicao.response.status_code == int(status), f'mensagem: "{mandar_requisicao.response.text}"'
+
+@then(parsers.parse('o JSON da resposta deve conter "{atributo}": "{string}"'))
+def checar_mensagem(atributo, string):
+ response_json = mandar_requisicao.response.json()
+
+ assert response_json.get(atributo) == string, (
+ f"Erro: Esperado '{atributo}': '{string}', obtido '{response_json.get(atributo)}'"
+ )
+
+
+@given(parsers.parse('a sala de id "{sala_id:d}" está disponível no dia "{data}" das "{start_time}" às "{end_time}"'))
+def sala_disponivel(sala_id, data, start_time, end_time):
+ url = f'{BASE_URL}/api/salas?data={data}&start_time={start_time}&end_time={end_time}'
+ response = requests.get(url)
+
+ assert response.status_code == 200, f"Erro ao buscar salas disponíveis: {response.text}"
+
+ sala_encontrada = any(sala['id'] == sala_id for sala in response.json())
+
+ assert sala_encontrada, (f'Sala {sala_id} não está disponível no horário solicitado ({data} das {start_time} '
+ f'às {end_time})')
+
+
+@given(parsers.parse('a sala de id "{sala_id:d}" não está disponível no dia "{data}" das "{start_time}" às "{end_time}"'))
+def sala_nao_disponivel(sala_id, data, start_time, end_time):
+ url = f'{BASE_URL}/api/salas?data={data}&start_time={start_time}&end_time={end_time}'
+ response = requests.get(url)
+
+ assert response.status_code == 200, f"Erro ao buscar salas disponíveis: {response.text}"
+
+ sala_encontrada = any(sala['id'] == sala_id for sala in response.json())
+
+ assert not sala_encontrada, (f'Sala {sala_id} está disponível no horário solicitado ({data} das {start_time} '
+ f'às {end_time})')
\ No newline at end of file
diff --git a/backend/testes/conftest.py b/backend/testes/conftest.py
new file mode 100644
index 00000000..fe06c059
--- /dev/null
+++ b/backend/testes/conftest.py
@@ -0,0 +1,109 @@
+import pytest
+from flask import Flask
+from backend.rotas.criar_solicitacao_manutencao import criar_manutencao_bp
+from backend.rotas.criar_solicitacao_recursos import criar_recursos_bp
+from backend.rotas.editar_solicitacao_manutencao import editar_manutencao_bp
+from backend.rotas.editar_solicitacao_recursos import editar_recursos_bp
+from backend.rotas.excluir_solicitacao_manutencao import excluir_manutencao_bp
+from backend.rotas.excluir_solicitacao_recursos import excluir_recursos_bp
+from backend.rotas.criarReview import criar_review_bp
+from backend.rotas.atualizarReview import atualizar_review_bp
+from backend.rotas.deletarReview import deletar_review_bp
+from backend.rotas.obterReview import obter_review_bp
+from backend.rotas.listarReview import listar_reviews_bp
+from backend.modelo.extensao import db
+from backend.modelo.solicitacaomanutencao import SolicitacaoManutencao
+from backend.modelo.solicitacaorecursos import SolicitacaoRecursos
+from backend.modelo.reviewSala import ReviewSala
+from backend.modelo.sala import Sala
+from backend.modelo.reserva import Reserva
+from ..rotas.cadastro import cadastro_bp
+from ..rotas.login import login_bp
+from ..modelo.extensao import db
+from ..modelo.usuario import Usuario
+from werkzeug.security import generate_password_hash
+
+@pytest.fixture(scope="module")
+def app():
+ aplicacao = Flask(__name__)
+ aplicacao.register_blueprint(criar_manutencao_bp)
+ aplicacao.register_blueprint(criar_recursos_bp)
+ aplicacao.register_blueprint(editar_manutencao_bp)
+ aplicacao.register_blueprint(editar_recursos_bp)
+ aplicacao.register_blueprint(excluir_manutencao_bp)
+ aplicacao.register_blueprint(excluir_recursos_bp)
+ aplicacao.register_blueprint(cadastro_bp)
+ aplicacao.register_blueprint(login_bp)
+ aplicacao.register_blueprint(criar_review_bp)
+ aplicacao.register_blueprint(atualizar_review_bp)
+ aplicacao.register_blueprint(deletar_review_bp)
+ aplicacao.register_blueprint(obter_review_bp)
+ aplicacao.register_blueprint(listar_reviews_bp)
+ aplicacao.config["TESTING"] = True
+ aplicacao.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///users.db"
+ aplicacao.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
+
+ with aplicacao.app_context():
+ db.init_app(aplicacao)
+ db.create_all()
+ yield aplicacao
+ db.session.remove()
+ db.drop_all()
+
+@pytest.fixture(scope="module")
+def client(app):
+ with app.test_client() as client:
+ yield client
+
+@pytest.fixture(scope="module", autouse=True)
+def setup_database(app):
+ """Popula o banco de dados com usuários de teste antes dos testes rodarem."""
+ with app.app_context():
+ db.create_all()
+
+ usuario1 = Usuario(
+ nome="Demosténes",
+ cpf="126.456.789-00",
+ email="demostenes@example.com",
+ professor="N",
+ siape=None,
+ senha=generate_password_hash("SecurePassword123"),
+ )
+
+ usuario2 = Usuario(
+ nome="Vanessa",
+ cpf="321.879.789-33",
+ email="vanessa@example.com",
+ professor="S",
+ siape="101010",
+ senha=generate_password_hash("12345678"),
+ )
+
+ manutencao1 = SolicitacaoManutencao(
+ reserva_id=1,
+ descricao="Mesa quebrada."
+ )
+
+ # Criando solicitações de recursos
+ recurso1 = SolicitacaoRecursos(
+ reserva_id=2,
+ recursos="Projetor, Teclado",
+ itens_nao_listados="Extensão elétrica",
+ observacoes="Para aula prática"
+ )
+# recurso2 = SolicitacaoRecursos(
+# reserva_id=3,
+# descricao="Necessidade de cadeiras extras.",
+# quantidade=5
+# )
+
+ db.session.add_all([manutencao1, recurso1])
+ db.session.add_all([usuario1, usuario2])
+ db.session.commit()
+ yield
+ db.session.remove()
+ db.drop_all()
+
+@pytest.fixture
+def contexto():
+ return {}
diff --git a/backend/testes/test_atualizarReview.py b/backend/testes/test_atualizarReview.py
new file mode 100644
index 00000000..0bdc2682
--- /dev/null
+++ b/backend/testes/test_atualizarReview.py
@@ -0,0 +1,58 @@
+import json
+import pytest
+import sys
+import os
+from pathlib import Path
+sys.path.append(str(Path(__file__).resolve().parent.parent))
+from backend.modelo.extensao import db
+from backend.modelo.reviewSala import ReviewSala
+from flask.testing import FlaskClient
+from datetime import datetime
+
+@pytest.fixture(scope="module")
+def criar_review(app):
+ with app.app_context():
+ review = ReviewSala(
+ reserva_id=1,
+ sala_id=2,
+ usuario_id=3,
+ nota=4,
+ comentario="Sala boa, mas com algumas falhas.",
+ )
+ db.session.add(review)
+ db.session.commit()
+ db.session.refresh(review)
+
+ return review
+
+
+def test_atualizar_review_existente(client, criar_review, app):
+ dados_atualizados = {
+ "nota": 5,
+ "comentario": "Modificações feitas, a sala está impecável agora!"
+ }
+
+ response = client.put(f"/api/reviews/{criar_review.id}", json=dados_atualizados)
+
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert data['mensagem'] == "Avaliação atualizada com sucesso!"
+
+ with app.app_context():
+ review_atualizado = db.session.get(ReviewSala, criar_review.id)
+ assert review_atualizado.nota == 5
+ assert review_atualizado.comentario == "Modificações feitas, a sala está impecável agora!"
+
+def test_atualizar_review_nao_existente(client):
+ dados_atualizados = {
+ "nota": 5,
+ "comentario": "Falhas corrigidas, a sala está impecável!"
+ }
+
+ response = client.put("/api/reviews/9999", json=dados_atualizados)
+
+ assert response.status_code == 404
+
+ data = json.loads(response.data)
+ assert data['error'] == "Avaliação não encontrada para o ID fornecido."
\ No newline at end of file
diff --git a/backend/testes/test_cadastro_servicos.py b/backend/testes/test_cadastro_servicos.py
new file mode 100644
index 00000000..b3db7dd9
--- /dev/null
+++ b/backend/testes/test_cadastro_servicos.py
@@ -0,0 +1,89 @@
+from pytest_bdd import scenario, given, when, then, parsers
+import pytest
+
+# Cenários de teste_
+@scenario("../features/CadastroServico.feature", "Sucesso no cadastro de usuário")
+def teste_SucessoUsuario():
+ pass
+
+@scenario("../features/CadastroServico.feature", "Sucesso no cadastro de professor")
+def teste_SucessoProfessor():
+ pass
+
+@scenario("../features/CadastroServico.feature", "Fracasso no cadastro por campos obrigatórios não preenchidos")
+def teste_ErroObrigatorio():
+ pass
+
+@scenario("../features/CadastroServico.feature", "Fracasso no cadastro por siape já registrado")
+def teste_ErroSiapeRegistrado():
+ pass
+
+@scenario("../features/CadastroServico.feature", "Fracasso no cadastro por duplicação de ID única")
+def teste_ErroCadastroDuplo():
+ pass
+
+@scenario("../features/CadastroServico.feature", "Fracasso no cadastro por senhas que não coincidem")
+def teste_ErroCadastroSenha():
+ pass
+
+@scenario("../features/CadastroServico.feature", "Fracasso no cadastro por formato inválido de email")
+def teste_ErroEmailInvalido():
+ pass
+
+@scenario("../features/CadastroServico.feature", "Fracasso no cadastro por formato inválido de CPF")
+def teste_ErroCpfInvalido():
+ pass
+
+# Given
+@given("o usuário deseja se cadastrar")
+def usuarioInicioCadastro(contexto):
+ contexto["dados_cadastro"] = {}
+
+# When
+@when(parsers.parse('ele informa o nome "{nome}"'))
+def informarNome(contexto, nome):
+ contexto["dados_cadastro"]["nome"] = nome
+
+@when(parsers.parse('ele informa o CPF "{cpf}"'))
+def informarCpf(contexto, cpf):
+ contexto["dados_cadastro"]["cpf"] = cpf
+
+@when(parsers.parse('ele informa o email "{email}"'))
+def informarEmail(contexto, email):
+ contexto["dados_cadastro"]["email"] = email
+
+@when(parsers.parse('ele informa se é professor "{professor}"'))
+def informarProfessor(contexto, professor):
+ contexto["dados_cadastro"]["professor"] = professor
+
+@when(parsers.parse('ele informa o SIAPE "{siape}"'))
+def informarSiape(contexto, siape):
+ contexto["dados_cadastro"]["siape"] = siape
+
+@when(parsers.parse('ele informa a senha "{senha}"'))
+def informarSenha(contexto, senha):
+ contexto["dados_cadastro"]["senha"] = senha
+
+@when(parsers.parse('ele informa a confirmação da senha "{confirmar_senha}"'))
+def confirmarSenha(contexto, confirmar_senha):
+ contexto["dados_cadastro"]["confirmarSenha"] = confirmar_senha
+
+@when(parsers.parse('ele envia uma requisição POST para "/cadastro"'))
+def enviarCadastro(client, contexto):
+ resposta = client.post("/cadastro", json=contexto["dados_cadastro"])
+ contexto["resposta"] = resposta
+
+@when(parsers.parse('ele deixa o campo "Confirmar Senha" com ""'))
+def senhaVazio(contexto):
+ pass
+# Then
+@then(parsers.parse('a resposta deve conter a mensagem "{mensagem}"'))
+def verificarMensagem(contexto, mensagem):
+ resposta_json = contexto["resposta"].get_json()
+ mensagem_real = resposta_json.get("message") or resposta_json.get("error")
+ assert mensagem_real == mensagem, f"Esperado: {mensagem}, Recebido: {mensagem_real}"
+
+@then(parsers.parse('o status code deve ser "{status_code}"'))
+def verificarStatusCode(contexto, status_code):
+ status_code = int(status_code)
+ assert contexto["resposta"].status_code == status_code, f"Esperado: {status_code}, Recebido: {contexto['resposta'].status_code}"
diff --git a/backend/testes/test_criarReview.py b/backend/testes/test_criarReview.py
new file mode 100644
index 00000000..aaac2962
--- /dev/null
+++ b/backend/testes/test_criarReview.py
@@ -0,0 +1,97 @@
+import pytest
+import requests
+from pytest_bdd import scenarios, given, when, then
+
+scenarios('../features/criarReview.feature')
+
+BASE_URL = "http://127.0.0.1:5000/api/reviews"
+
+@pytest.fixture
+def context():
+ return {}
+
+@given('que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id "1" para a sala_id "2"')
+@given('que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id ""')
+@given('que o professor Suruagy deseja fazer uma avaliação pós reserva com reserva_id "1" para a sala_id ""')
+def preparar_contexto(context):
+ context['url'] = BASE_URL
+
+@when('ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "2", usuario_id "3", nota "4" e comentário "Sala boa, mas com algumas falhas."')
+def enviar_review_valida(context):
+ payload = {
+ "reserva_id": 1,
+ "sala_id": 2,
+ "usuario_id": 3,
+ "nota": 4,
+ "comentario": "Sala boa, mas com algumas falhas."
+ }
+ context['response'] = requests.post(context['url'], json=payload)
+
+@when('ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "2", usuario_id "3", nota "" e comentário "Sala boa, mas sem computador!"')
+def enviar_review_sem_nota(context):
+ payload = {
+ "reserva_id": 1,
+ "sala_id": 2,
+ "usuario_id": 3,
+ "nota": None,
+ "comentario": "Sala boa, mas sem computador!"
+ }
+ context['response'] = requests.post(context['url'], json=payload)
+
+@when('ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "", usuario_id "3", nota "4" e comentário "Sala boa, mas sem computador!"')
+def enviar_review_sem_sala_id(context):
+ payload = {
+ "reserva_id": 1,
+ "sala_id": None,
+ "usuario_id": 3,
+ "nota": 4,
+ "comentario": "Sala boa, mas sem computador!"
+ }
+ context['response'] = requests.post(context['url'], json=payload)
+
+@when('ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "1", sala_id "2", usuario_id "", nota "4" e comentário "Sala boa, mas sem computador!"')
+def enviar_review_sem_usuario_id(context):
+ payload = {
+ "reserva_id": 1,
+ "sala_id": 2,
+ "usuario_id": None,
+ "nota": 4,
+ "comentario": "Sala boa, mas sem computador!"
+ }
+ context['response'] = requests.post(context['url'], json=payload)
+
+@when('ele envia uma requisição POST para "/api/reviews" com os dados reserva_id "", sala_id "2", usuario_id "3", nota "4" e comentário "Sala boa, mas sem computador!"')
+def enviar_review_sem_reserva_id(context):
+ payload = {
+ "reserva_id": None,
+ "sala_id": 2,
+ "usuario_id": 3,
+ "nota": 4,
+ "comentario": "Sala boa, mas sem computador!"
+ }
+ context['response'] = requests.post(context['url'], json=payload)
+
+@then('o sistema retorna "Avaliação criada com sucesso!" com o status 201')
+def validar_resposta_sucesso(context):
+ assert context['response'].status_code == 201
+ assert context['response'].json()["mensagem"] == "Avaliação criada com sucesso!"
+
+@then('o sistema retorna "A nota é obrigatória para avaliar a sala." com o status 400')
+def validar_resposta_sem_nota(context):
+ assert context['response'].status_code == 400
+ assert context['response'].json()["error"] == "A nota é obrigatória para avaliar a sala."
+
+@then('o sistema retorna "O ID da Sala é obrigatório para avaliar a sala." com o status 400')
+def validar_resposta_sem_sala_id(context):
+ assert context['response'].status_code == 400
+ assert context['response'].json()["error"] == "O ID da Sala é obrigatório para avaliar a sala."
+
+@then('o sistema retorna "O ID do Usuário é obrigatório para avaliar a sala." com o status 400')
+def validar_resposta_sem_usuario_id(context):
+ assert context['response'].status_code == 400
+ assert context['response'].json()["error"] == "O ID do Usuário é obrigatório para avaliar a sala."
+
+@then('o sistema retorna "O ID da Reserva é obrigatório para avaliar a sala." com o status 400')
+def validar_resposta_sem_reserva_id(context):
+ assert context['response'].status_code == 400
+ assert context['response'].json()["error"] == "O ID da Reserva é obrigatório para avaliar a sala."
diff --git a/backend/testes/test_deletarReview.py b/backend/testes/test_deletarReview.py
new file mode 100644
index 00000000..7429ef3d
--- /dev/null
+++ b/backend/testes/test_deletarReview.py
@@ -0,0 +1,44 @@
+import sys
+import os
+from pathlib import Path
+
+sys.path.append(str(Path(__file__).resolve().parent.parent))
+import pytest
+import json
+from datetime import datetime
+from backend.modelo.extensao import db
+from backend.modelo.reviewSala import ReviewSala
+
+
+@pytest.fixture
+def criar_review(app):
+ with app.app_context():
+ review = ReviewSala(
+ reserva_id=1,
+ sala_id=2,
+ usuario_id=3,
+ nota=4,
+ comentario="Sala boa, mas com algumas falhas.",
+ )
+ db.session.add(review)
+ db.session.commit()
+ db.session.refresh(review)
+ return review
+
+def test_deletar_review_existente(client, criar_review, app):
+ response = client.delete(f"/api/reviews/{criar_review.id}")
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+ assert data['mensagem'] == "Avaliação deletada com sucesso!"
+
+ with app.app_context():
+ review_deletado = db.session.get(ReviewSala, criar_review.id)
+ assert review_deletado is None
+
+def test_deletar_review_nao_existente(client):
+ response = client.delete("/api/reviews/9999")
+ assert response.status_code == 404
+
+ data = json.loads(response.data)
+ assert data['error'] == "Avaliação não encontrada para o ID fornecido."
\ No newline at end of file
diff --git a/backend/testes/test_listarReview.py b/backend/testes/test_listarReview.py
new file mode 100644
index 00000000..7cac8629
--- /dev/null
+++ b/backend/testes/test_listarReview.py
@@ -0,0 +1,62 @@
+import sys
+import os
+from pathlib import Path
+sys.path.append(str(Path(__file__).resolve().parent.parent))
+import json
+import pytest
+from datetime import datetime
+from pytest_bdd import scenarios, given, when, then
+
+scenarios('../features/listarReview.feature')
+
+from backend.modelo.extensao import db
+from backend.modelo.reviewSala import ReviewSala
+
+
+@pytest.fixture
+def criar_avaliacao(app):
+ with app.app_context():
+ review = ReviewSala(
+ reserva_id=1,
+ sala_id=2,
+ usuario_id=3,
+ nota=5,
+ comentario="Sala excelente, as mudanças foram feitas e ficou ótima.",
+ )
+ db.session.add(review)
+ db.session.commit()
+ db.session.refresh(review)
+ return review
+
+@given('o professor Suruagy deseja consultar as avaliações presentes no sistema e existem avaliações cadastradas')
+def existem_avaliacoes(criar_avaliacao):
+ pass
+
+@given('o professor Suruagy deseja consultar as avaliações presentes no sistema e não existem avaliações cadastradas')
+def nao_existem_avaliacoes(app):
+ with app.app_context():
+ db.session.query(ReviewSala).delete()
+ db.session.commit()
+
+@when('ele envia uma requisição GET para "/api/reviews"', target_fixture="enviar_requisicao_listar")
+def enviar_requisicao_listar(client):
+ return client.get("/api/reviews")
+
+@then('o sistema lista todas as avaliações que foram postadas anteriormente para todas as salas com o status 200 OK')
+def validar_listagem_sucesso(enviar_requisicao_listar):
+ response = enviar_requisicao_listar
+ assert response.status_code == 200
+ data = json.loads(response.data)
+ assert isinstance(data, list)
+ assert len(data) > 0
+
+@then('o sistema não encontra nenhuma avaliação no sistema')
+def validar_listagem_vazia(enviar_requisicao_listar):
+ response = enviar_requisicao_listar
+ assert response.status_code == 404
+
+@then('exibe a mensagem de erro "Nenhuma avaliação encontrada." com o status 404 NOT FOUND')
+def validar_mensagem_erro(enviar_requisicao_listar):
+ response = enviar_requisicao_listar
+ data = json.loads(response.data)
+ assert data['error'] == "Nenhuma avaliação encontrada."
\ No newline at end of file
diff --git a/backend/testes/test_login_servicos.py b/backend/testes/test_login_servicos.py
new file mode 100644
index 00000000..6fdb94dc
--- /dev/null
+++ b/backend/testes/test_login_servicos.py
@@ -0,0 +1,57 @@
+from pytest_bdd import scenario, given, when, then, parsers
+import pytest
+
+# Cenários de teste_
+@scenario("../features/loginServico.feature", "Sucesso no login")
+def teste_SucessoLogin():
+ pass
+
+@scenario("../features/loginServico.feature", "Fracasso no login por senha incorreta")
+def teste_FracassoLogin():
+ pass
+
+@scenario("../features/loginServico.feature", "Fracasso no login por falta de email ou senha")
+def teste_FracassoLoginSemEmailOuSenha():
+ pass
+
+# Given
+@given(parsers.parse('o usuário possui o email "{email}" e a senha "{senha}" válidos'))
+def usuarioCredenciais(contexto, email, senha):
+ contexto["email"] = email
+ contexto["senha"] = senha
+
+@given(parsers.parse('o usuário possui o email "{email}" válido e a senha "{senha}" inválida'))
+def usuarioSenhaInvalida(contexto, email, senha):
+ contexto["email"] = email
+ contexto["senha"] = senha
+
+@given("o usuário envia uma requisição sem email ou senha")
+def usuarioSemCredenciais(contexto):
+ contexto["email"] = ""
+ contexto["senha"] = ""
+
+# When
+@when(parsers.parse('ele envia uma requisição POST para "/api/login" com os dados "{email}" e "{senha}"'))
+def enviarRequisicaoLogin(client, contexto, email, senha):
+ resposta = client.post("/", json={"email": email, "senha": senha})
+ contexto["resposta"] = resposta
+
+
+
+# Then
+@then(parsers.parse('a resposta deve conter o email "{email}" e a mensagem "success" igual a True'))
+def verificarRespostaSucesso(contexto, email):
+ respostaJson = contexto["resposta"].get_json()
+ assert respostaJson["usuario"]["email"] == email, f"Esperado: {email}, Recebido: {respostaJson}"
+ assert respostaJson["success"] == True, f"Esperado: True, Recebido: {respostaJson['success']}"
+
+@then(parsers.parse('a resposta deve conter a mensagem "{mensagem}"'))
+def verificarRespostaFalha(contexto, mensagem):
+ respostaJson = contexto["resposta"].get_json()
+ assert respostaJson["error"] == mensagem, f"Esperado: {mensagem}, Recebido: {respostaJson}"
+
+
+@then(parsers.parse('o status code deve ser "{status_code}"'))
+def verificarStatusCode(contexto, status_code):
+ status_code = int(status_code)
+ assert contexto["resposta"].status_code == status_code, f"Esperado: {status_code}, Recebido: {contexto['resposta'].status_code}"
diff --git a/backend/testes/test_manutencao.py b/backend/testes/test_manutencao.py
new file mode 100644
index 00000000..b26ecb0c
--- /dev/null
+++ b/backend/testes/test_manutencao.py
@@ -0,0 +1,77 @@
+from pytest_bdd import scenario, given, when, then, parsers
+import pytest
+
+# Cenários de teste_
+@scenario("../features/manutencao.feature", "sucesso ao criar uma solicitação de manutenção para uma reserva concluída")
+def teste_SucessoCriarManutencao():
+ pass
+
+@scenario("../features/manutencao.feature", "fracasso ao criar uma solicitação de manutenção sem preencher o campo descricao")
+def teste_FracassoCriarManutencao():
+ pass
+
+@scenario("../features/manutencao.feature", "sucesso ao editar uma solicitação de manutenção existente")
+def teste_SucessoEditarManutencao():
+ pass
+
+@scenario("../features/manutencao.feature", "fracasso ao editar solicitação de manutenção sem preencher o campo descricao")
+def teste_FracassoEditarManutencao():
+ pass
+
+@scenario("../features/manutencao.feature", "sucesso ao excluir uma solicitação de manutenção existente")
+def teste_SucessoExcluirManutencao():
+ pass
+
+# Given
+@given(parsers.parse('o professor possui uma reserva de sala reserva_id "{reserva_id}" que já foi encerrada'))
+def reserva_encerrada(contexto, reserva_id):
+ contexto["reserva_id"] = int(reserva_id)
+
+@given(parsers.parse('o professor já criou uma solicitação de manutenção associada a reserva_id "{reserva_id}"'))
+def criar_solicitacao_previa(contexto, reserva_id):
+ contexto["reserva_id"] = int(reserva_id)
+ contexto["descricao"] = "Mesa quebrada."
+ contexto["manutencao_id"] = 1 # Simulando um ID gerado pelo sistema
+
+# When
+@when(parsers.parse('ele envia uma requisição POST /solicitacoes/manutencao com os dados: reserva_id: "{reserva_id}", descricao: "{descricao}"'))
+def criar_solicitacao(client, contexto, reserva_id, descricao):
+ resposta = client.post("/solicitacoes/manutencao", json={"reserva_id": reserva_id, "descricao": descricao})
+ contexto["resposta"] = resposta
+ contexto["descricao"] = descricao
+
+@when(parsers.parse('ele envia uma requisição PUT /solicitacoes/manutencao/{id} contendo o ID da solicitação de manutenção e a alteração descricao: "{descricao}"'))
+def editar_solicitacao(client, contexto, descricao):
+ import json
+ manutencao_id = contexto["manutencao_id"]
+ resposta = client.put(f"/solicitacoes/manutencao/{manutencao_id}", json={"descricao": descricao})
+ contexto["resposta"] = resposta
+ dados = json.loads(resposta.data)
+ contexto["descricao"] = dados.get("descricao")
+
+@when(parsers.parse('ele envia uma requisição DELETE /solicitacoes/manutencao/{id}'))
+def deletar_solicitacao(client, contexto):
+ manutencao_id = contexto["manutencao_id"]
+ resposta = client.delete(f"/solicitacoes/manutencao/{manutencao_id}")
+ contexto["resposta"] = resposta
+
+
+# Then
+@then(parsers.parse('o sistema retorna "{mensagem_tipo}" "{mensagem}" e um status "{status}"'))
+def verificar_resposta(contexto, mensagem_tipo, mensagem, status):
+ resposta = contexto["resposta"]
+ assert resposta.status_code == int(status), f"{resposta}"
+ assert resposta.get_json()[mensagem_tipo] == mensagem
+
+@then(parsers.parse('a reserva reserva_id: "{reserva_id}" possui uma solicitação de manutenção com descricao: "{descricao}"'))
+def verificar_solicitacao_de_manutencao(contexto, reserva_id, descricao):
+ assert contexto["reserva_id"] == int(reserva_id)
+ assert contexto["descricao"] == descricao
+
+@then(parsers.parse('o sistema atualiza os detalhes da solicitação com descricao: "{descricao}"'))
+def verificar_solicitacao_de_manutencao(contexto, descricao):
+ assert contexto["descricao"] == descricao
+
+@then(parsers.parse('o sistema remove a solicitação do banco de dados e retorna um status "{status}"'))
+def verificar_exclusao_de_manutencao(contexto, status):
+ assert contexto["resposta"].status_code == int(status)
\ No newline at end of file
diff --git a/backend/testes/test_obterReview.py b/backend/testes/test_obterReview.py
new file mode 100644
index 00000000..85fba458
--- /dev/null
+++ b/backend/testes/test_obterReview.py
@@ -0,0 +1,48 @@
+import sys
+import os
+from pathlib import Path
+sys.path.append(str(Path(__file__).resolve().parent.parent))
+
+import json
+import pytest
+from datetime import datetime
+
+from backend.modelo.extensao import db
+from backend.modelo.reviewSala import ReviewSala
+
+@pytest.fixture(scope="module")
+def criar_review(app):
+ with app.app_context():
+ review = ReviewSala(
+ reserva_id=1,
+ sala_id=2,
+ usuario_id=3,
+ nota=5,
+ comentario="Sala excelente, as mudanças foram feitas e ficou ótima.",
+ )
+ db.session.add(review)
+ db.session.commit()
+ db.session.refresh(review)
+ return review
+
+def test_obter_review_existente(client, criar_review):
+ response = client.get(f"/api/reviews/{criar_review.id}")
+
+ assert response.status_code == 200
+
+ data = json.loads(response.data)
+
+ assert data['id'] == criar_review.id
+ assert data['reserva_id'] == 1
+ assert data['sala_id'] == 2
+ assert data['usuario_id'] == 3
+ assert data['nota'] == 5
+ assert data['comentario'] == "Sala excelente, as mudanças foram feitas e ficou ótima."
+
+def test_obter_review_inexistente(client):
+ response = client.get("/api/reviews/9999")
+
+ assert response.status_code == 404
+
+ data = json.loads(response.data)
+ assert data['error'] == "Avaliação não encontrada para o ID fornecido."
\ No newline at end of file
diff --git a/backend/testes/test_recursos.py b/backend/testes/test_recursos.py
new file mode 100644
index 00000000..15fcb0c2
--- /dev/null
+++ b/backend/testes/test_recursos.py
@@ -0,0 +1,102 @@
+from pytest_bdd import scenario, given, when, then, parsers
+import pytest
+
+# Cenários de teste
+@scenario("../features/recursos.feature", "sucesso ao criar solicitação de recursos para uma reserva ativa com todos os campos preenchidos")
+def teste_SucessoCriarSolicitacao():
+ pass
+
+@scenario("../features/recursos.feature", "fracasso ao criar solicitação de recursos com campos preenchidos com espaços ou não preenchidos")
+def teste_FracassoCriarSolicitacaoCamposVazios():
+ pass
+
+@scenario("../features/recursos.feature", "fracasso ao criar solicitação de recursos com apenas o campo observacoes preenchido")
+def teste_FracassoCriarSolicitacaoSomenteObservacoes():
+ pass
+
+@scenario("../features/recursos.feature", "sucesso ao criar solicitação de recursos sem preencher o campo itens_nao_listados")
+def teste_SucessoCriarSolicitacaoSemItensNaoListados():
+ pass
+
+@scenario("../features/recursos.feature", "sucesso ao criar solicitação de recursos sem preencher o campo itens_nao_listados e o campo observacoes")
+def teste_SucessoCriarSolicitacaoBasica():
+ pass
+
+@scenario("../features/recursos.feature", "sucesso ao criar solicitação de recursos com o campo de recursos vazio e apenas especificando os itens não listados")
+def teste_SucessoCriarSolicitacaoComItensNaoListados():
+ pass
+
+@scenario("../features/recursos.feature", "sucesso ao criar solicitação de recursos com o campo de recursos vazio e especificando os itens não listados e as observacoes")
+def teste_SucessoCriarSolicitacaoComItensNaoListadosObs():
+ pass
+
+@scenario("../features/recursos.feature", "sucesso ao editar uma solicitação de recursos existente")
+def teste_SucessoEditarSolicitacao():
+ pass
+
+@scenario("../features/recursos.feature", "fracasso ao editar uma solicitação de recursos com apenas o campo observacoes preenchido")
+def teste_FracassoEditarSolicitacao():
+ pass
+
+@scenario("../features/recursos.feature", "sucesso ao excluir uma solicitação de recursos existente")
+def teste_SucessoExcluirSolicitacao():
+ pass
+
+# Given
+@given(parsers.parse('o professor possui uma reserva ativa com reserva_id "{reserva_id}"'))
+def reserva_ativa(contexto, reserva_id):
+ contexto["reserva_id"] = int(reserva_id)
+
+@given(parsers.parse('o professor possui uma solicitação de recursos associada a reserva_id "{reserva_id}"'))
+def criar_solicitacao_previa(contexto, reserva_id):
+ contexto["reserva_id"] = int(reserva_id)
+ contexto["recursos"] = "Projetor, Teclado"
+ contexto["solicitacao_id"] = 1
+
+# When
+@when(parsers.parse('ele envia uma requisição POST /solicitacoes/recursos com os dados: reserva_id: "{reserva_id}", recursos: "{recursos}", itens_nao_listados: "{itens_nao_listados}", observacoes: "{observacoes}"'))
+def criar_solicitacao(client, contexto, reserva_id, recursos, itens_nao_listados, observacoes):
+ resposta = client.post("/solicitacoes/recursos", json={"reserva_id": reserva_id, "recursos": recursos, "itens_nao_listados": itens_nao_listados, "observacoes": observacoes})
+ contexto["resposta"] = resposta
+ contexto["recursos"] = recursos
+ contexto["itens_nao_listados"] = itens_nao_listados
+ contexto["observacoes"] = observacoes
+
+@when(parsers.parse('ele envia uma requisição PUT /solicitacoes/recursos/{id} contendo o ID da solicitação e os novos detalhes da solicitação recursos: "{recursos}", observacoes: "{observacoes}"'))
+def editar_solicitacao(client, contexto, recursos, observacoes):
+ import json
+ solicitacao_id = contexto["solicitacao_id"]
+ resposta = client.put(f"/solicitacoes/recursos/{solicitacao_id}", json={"recursos": recursos, "observacoes": observacoes})
+ contexto["resposta"] = resposta
+ dados = json.loads(resposta.data)
+ contexto["recursos"] = recursos
+ contexto["observacoes"] = observacoes
+
+@when(parsers.parse('ele envia uma requisição DELETE /solicitacoes/recursos/{id} contendo o ID da solicitação'))
+def deletar_solicitacao(client, contexto):
+ solicitacao_id = contexto["solicitacao_id"]
+ resposta = client.delete(f"/solicitacoes/recursos/{solicitacao_id}")
+ contexto["resposta"] = resposta
+
+# Then
+@then(parsers.parse('o sistema retorna "{mensagem_tipo}" "{mensagem}" e um status "{status}"'))
+def verificar_resposta(contexto, mensagem_tipo, mensagem, status):
+ resposta = contexto["resposta"]
+ assert resposta.status_code == int(status)
+ assert resposta.get_json()[mensagem_tipo] == mensagem
+
+@then(parsers.parse('a reserva_id "{reserva_id}" possui uma solicitação com recursos "{recursos}", itens_nao_listados "{itens_nao_listados}" e observacoes "{observacoes}"'))
+def verificar_solicitacao(contexto, reserva_id, recursos, itens_nao_listados, observacoes):
+ assert contexto["reserva_id"] == int(reserva_id)
+ assert contexto["recursos"] == recursos
+ assert contexto["itens_nao_listados"] == itens_nao_listados
+ assert contexto["observacoes"] == observacoes
+
+@then(parsers.parse('o sistema atualiza os detalhes da solicitação: recursos: "{recursos}", observacoes: "{observacoes}"'))
+def verificar_solicitacao_de_manutencao(contexto, recursos, observacoes):
+ assert contexto["recursos"] == recursos
+ assert contexto["observacoes"] == observacoes
+
+@then(parsers.parse('o sistema remove a solicitação do banco de dados e retorna um status "{status}"'))
+def verificar_exclusao(contexto, status):
+ assert contexto["resposta"].status_code == int(status)
diff --git a/backend/testes/test_reservas.py b/backend/testes/test_reservas.py
new file mode 100644
index 00000000..2e5cb556
--- /dev/null
+++ b/backend/testes/test_reservas.py
@@ -0,0 +1,78 @@
+import requests
+from pytest_bdd import scenario, when, then, given, parsers
+from backend.testes.common_step_definitions import *
+
+BASE_URL = 'http://127.0.0.1:5000'
+
+
+@scenario('../features/reservas.feature', 'Criar uma reserva com sucesso')
+def test_criar_uma_reserva_com_sucesso():
+ pass
+
+@scenario('../features/reservas.feature', 'Erro ao tentar reservar uma sala já ocupada')
+def test_erro_ao_tentar_reservar_sala_ocupada():
+ pass
+
+@scenario('../features/reservas.feature', 'Erro ao tentar reservar com campos ausentes')
+def test_erro_ao_tentar_reservar_campos_ausentes():
+ pass
+
+@scenario('../features/reservas.feature', 'Cancelar uma reserva com sucesso')
+def test_cancelar_uma_reserva_com_sucesso():
+ pass
+
+@scenario('../features/reservas.feature', 'Erro ao tentar cancelar uma reserva inexistente')
+def test_cancelar_uma_reserva_inexistente():
+ pass
+
+
+@given(parsers.parse('o professor de id "{professor_id:d}" não tem uma reserva no dia "{data}" '
+ 'das "{start_time}" às "{end_time}"'))
+def professor_disponivel(professor_id, data, start_time, end_time):
+ url = f'{BASE_URL}/api/reservas/{professor_id}'
+ response = requests.get(url)
+ reservas = response.json()
+
+ for reserva in reservas:
+ if reserva['data'] == data and reserva['status'] == ['ativa']:
+ assert (start_time >= reserva['end_time'] or end_time <= reserva['start_time']), \
+ f'Professor {professor_id} já tem uma reserva nesse horário'
+
+
+@given(parsers.parse('o professor de id "{professor_id:d}" tem uma reserva ativa de id "{reserva_id}"'))
+def professor_disponivel(professor_id, reserva_id):
+ url = f'{BASE_URL}/api/reservas/{professor_id}'
+ response = requests.get(url)
+
+ assert response.status_code == 200, f'Erro ao buscar reservas do professor {professor_id}'
+
+ reservas = response.json()
+
+ reserva_encontrada = any(
+ reserva['id'] == int(reserva_id) and reserva["status"] for reserva in reservas
+ )
+
+ assert reserva_encontrada, f"O professor {professor_id} não tem uma reserva ativa de id {reserva_id}"
+
+
+@then(parsers.parse('o JSON da reserva deve conter "{atributo}": "{valor}"'))
+def checar_atributo(atributo, valor):
+ response_json = mandar_requisicao.response.json()
+
+ assert "reservation" in response_json, (
+ f"Erro: 'reservation' não encontrado na resposta:\n{response_json}"
+ )
+
+ assert atributo in response_json["reservation"], (
+ f"Erro: Atributo '{atributo}' não encontrado dentro de 'reservation':\n{response_json}"
+ )
+
+ if valor.isdigit():
+ valor = int(valor)
+
+ valor_real = response_json["reservation"][atributo]
+
+ assert valor_real == valor, (
+ f"Erro: Para '{atributo}', esperado '{valor}' ({type(valor).__name__}), "
+ f"obtido '{valor_real}' ({type(valor_real).__name__})"
+ )
\ No newline at end of file
diff --git a/backend/testes/test_salas.py b/backend/testes/test_salas.py
new file mode 100644
index 00000000..d3be2dc6
--- /dev/null
+++ b/backend/testes/test_salas.py
@@ -0,0 +1,126 @@
+import json
+import requests
+from pytest_bdd import scenario, when, then, given, parsers
+
+from backend.testes.common_step_definitions import *
+
+
+BASE_URL = 'http://127.0.0.1:5000'
+
+@scenario('../features/salas.feature', 'Criar sala com sucesso')
+def test_criar_sala_com_sucesso():
+ pass
+
+@scenario('../features/salas.feature', 'Buscar todas as salas disponíveis')
+def test_buscar_salas():
+ pass
+
+@scenario('../features/salas.feature', 'Erro ao buscar salas sem data preenchida')
+def test_erro_ao_buscar_salas_data():
+ pass
+
+@scenario('../features/salas.feature', 'Erro ao buscar salas com tempo não informado')
+def test_erro_ao_buscar_salas_tempo():
+ pass
+
+@scenario('../features/salas.feature', 'Erro ao tentar deletar sala com reserva ativa')
+def test_erro_ao_tentar_deletar_sala_com_reserva():
+ pass
+
+@given(parsers.parse('a sala de id "{sala_id}" tem uma reserva ativa'))
+def sala_tem_reserva_ativa(sala_id):
+ sala_id = int(sala_id)
+
+ response = requests.get(f"{BASE_URL}/api/reservas")
+ assert response.status_code == 200, f"Erro ao buscar reservas: {response.text}"
+
+ reservas = response.json()
+
+ reserva_existente = any(
+ reserva for reserva in reservas if reserva["sala_id"] == sala_id and reserva["status"] == "ativa"
+ )
+
+ if not reserva_existente:
+ reserva_body = {
+ "sala_id": sala_id,
+ "data": "2025-02-25",
+ "start_time": "14:00",
+ "end_time": "15:00"
+ }
+
+ reserva_response = requests.post(f"{BASE_URL}/api/reservas/3", json=reserva_body) # Aqui eu crio só para o professor de id 3
+ assert reserva_response.status_code == 201, f"Erro ao criar reserva ativa: {reserva_response.text}"
+
+
+@given(parsers.parse('existe uma sala com nome "{nome}"'))
+def existe_uma_sala_com_nome(nome):
+ response = requests.get(f"{BASE_URL}/api/salas")
+
+ salas = response.json()
+
+
+ sala_existente = next((sala for sala in salas if sala["nome"] == nome), None)
+
+ if not sala_existente:
+ sala_body = {
+ "nome": nome,
+ "tipo": "Reunião",
+ "lugares": 10,
+ "andar": 0,
+ "equipamentos": ["Projetor"]
+ }
+
+ sala_response = requests.post(f"{BASE_URL}/api/salas", json=sala_body)
+ assert sala_response.status_code == 201, f"Erro ao criar sala: {response.text}"
+
+@given(parsers.parse('não existe uma sala com nome "{nome}"'))
+def sala_nao_existe(nome):
+
+ response = requests.get(f"{BASE_URL}/api/salas")
+ assert response.status_code == 200, "Erro ao buscar salas: " + response.text
+
+ salas = response.json()
+
+ for sala in salas:
+ if sala["nome"] == nome:
+ sala_id = sala["id"]
+
+ # Deleta se necessário
+ delete_response = requests.delete(f"{BASE_URL}/api/salas/{sala_id}")
+ assert delete_response.status_code in [200, 204], "Erro ao deletar sala: " + delete_response.text
+
+
+@then(parsers.parse('o JSON da sala deve conter "{atributo}": "{valor}"'))
+def checar_atributo(atributo, valor):
+ response_json = mandar_requisicao.response.json()
+
+ assert "sala" in response_json, f"Erro; 'sala' não encontrado na resposta: \n{response_json}"
+
+ assert atributo in response_json["sala"], \
+ f"Erro: Atributo '{atributo}' não encontrado dentro de 'sala': \n{response_json}"
+
+ if valor.isdigit():
+ valor = int(valor)
+
+ valor_real = response_json["sala"][atributo]
+
+ assert valor_real == valor, (
+ f"Erro: Para '{atributo}', esperado '{valor}' ({type(valor).__name__}), "
+ f"obtido '{valor_real}' ({type(valor_real).__name__})"
+ )
+
+
+@then('o JSON da resposta deve conter uma lista de salas com todos os dados')
+def checar_lista_de_salas():
+ response_json = mandar_requisicao.response.json()
+
+ assert isinstance(response_json, list), f'Uma lista de salas não for retornada'
+ assert len(response_json) > 0, f'A lista de salas retornada está vazia'
+
+ for sala in response_json:
+ assert "id" in sala, f"'id' faltando: {sala}"
+ assert "tipo" in sala, f"'tipo' faltando: {sala}"
+ assert "lugares" in sala, f"'lugares' faltando: {sala}"
+ assert 'andar' in sala, f"'andar' faltando: {sala}"
+ assert 'equipamentos' in sala, f"'equipamentos' faltando: {sala}"
+ assert 'nome' in sala, f"'nome' faltando: {sala}"
diff --git a/cypress/e2e/features/cadastro.feature b/cypress/e2e/features/cadastro.feature
new file mode 100644
index 00000000..dcd24e2b
--- /dev/null
+++ b/cypress/e2e/features/cadastro.feature
@@ -0,0 +1,42 @@
+Feature: Cadastro de usuário no frontend
+
+ Scenario: Cadastro bem-sucedido
+ Given o usuário está na página de cadastro
+ When ele preenche o campo de nome com "Demóstenes Silva"
+ And ele preenche o campo de CPF com "123.456.789-00"
+ And ele preenche o campo de email com "demostenes@example.com"
+ And ele preenche o campo de senha com "SecurePassword123"
+ And ele preenche o campo de confirmar senha com "SecurePassword123"
+ And ele seleciona a opção "Não" para professor
+ And ele clica no botão "Criar"
+ Then ele deve ver uma mensagem de sucesso
+ And deve haver um botão para voltar à área de login
+
+ Scenario: Cadastro como professor
+ Given o usuário está na página de cadastro
+ When ele preenche o campo de nome com "Prof. Demóstenes"
+ And ele preenche o campo de CPF com "987.654.321-00"
+ And ele preenche o campo de email com "prof.demostenes@example.com"
+ And ele preenche o campo de senha com "SecurePassword123"
+ And ele preenche o campo de confirmar senha com "SecurePassword123"
+ And ele seleciona a opção "Sim, sou professor" para professor
+ And ele preenche o campo SIAPE com "123456"
+ And ele clica no botão "Criar"
+ Then ele deve ver uma mensagem de sucesso
+ And deve haver um botão para voltar à área de login
+
+ Scenario: Erro no cadastro com senhas diferentes
+ Given o usuário está na página de cadastro
+ When ele preenche o campo de nome com "Demóstenes Silva"
+ And ele preenche o campo de CPF com "123.456.789-00"
+ And ele preenche o campo de email com "demostenes@example.com"
+ And ele preenche o campo de senha com "SecurePassword123"
+ And ele preenche o campo de confirmar senha com "DifferentPassword456"
+ And ele seleciona a opção "Não" para professor
+ And ele clica no botão "Criar"
+ Then ele deve ver uma mensagem de erro "As senhas não coincidem."
+
+ Scenario: Voltar para login a partir do cadastro
+ Given o usuário está na página de cadastro
+ When ele clica no link "Já possuo uma conta"
+ Then ele deve ser redirecionado para a página de login
\ No newline at end of file
diff --git a/cypress/e2e/features/common-step-definitions/cadastro.step.ts b/cypress/e2e/features/common-step-definitions/cadastro.step.ts
new file mode 100644
index 00000000..196b6180
--- /dev/null
+++ b/cypress/e2e/features/common-step-definitions/cadastro.step.ts
@@ -0,0 +1,77 @@
+import { Given, When, Then } from "@badeball/cypress-cucumber-preprocessor";
+
+// URL da página de cadastro
+const cadastroUrl = "/cadastro";
+const loginUrl = "/";
+
+// Elementos da página baseados no seu HTML
+const nomeInput = 'input[type="text"][placeholder="Nome"]';
+const cpfInput = 'input[type="text"][placeholder="CPF"]';
+const emailInput = 'input[type="email"][placeholder="Email"]';
+const senhaInput = 'input[type="password"][placeholder="Senha"]';
+const confirmarSenhaInput = 'input[type="password"][placeholder="Confirmar senha"]';
+const professorSelect = 'select';
+const siapeInput = 'input[type="text"][placeholder="SIAPE"]';
+const criarButton = 'button:contains("Criar")';
+const errorMessageContainer = '.error-message';
+const successMessageContainer = 'div[style*="color: green"]';
+const voltarLoginButton = 'button:contains("Voltar à Área de Login")';
+const jaPossuoContaLink = 'span.link:contains("Já possuo uma conta")';
+
+// Steps para cadastro
+Given("o usuário está na página de cadastro", () => {
+ cy.visit(cadastroUrl);
+ cy.contains("Sistema de Agendamento e").should("be.visible");
+});
+
+When("ele preenche o campo de nome com {string}", (nome: string) => {
+ cy.get(nomeInput).clear().type(nome);
+});
+
+When("ele preenche o campo de CPF com {string}", (cpf: string) => {
+ cy.get(cpfInput).clear().type(cpf);
+});
+
+When("ele preenche o campo de email com {string}", (email: string) => {
+ cy.get(emailInput).clear().type(email);
+});
+
+When("ele preenche o campo de senha com {string}", (senha: string) => {
+ cy.get(senhaInput).clear().type(senha);
+});
+
+When("ele preenche o campo de confirmar senha com {string}", (senha: string) => {
+ cy.get(confirmarSenhaInput).clear().type(senha);
+});
+
+When("ele seleciona a opção {string} para professor", (opcao: string) => {
+ cy.get(professorSelect).select(opcao);
+});
+
+When("ele preenche o campo SIAPE com {string}", (siape: string) => {
+ cy.get(siapeInput).clear().type(siape);
+});
+
+When("ele clica no botão {string}", (buttonText: string) => {
+ cy.contains("button", buttonText).click();
+});
+
+When("ele clica no link {string}", (linkText: string) => {
+ cy.contains("span.link", linkText).click();
+});
+
+Then("ele deve ver uma mensagem de sucesso", () => {
+ cy.get(successMessageContainer).should("be.visible");
+});
+
+Then("deve haver um botão para voltar à área de login", () => {
+ cy.get(voltarLoginButton).should("be.visible");
+});
+
+Then("ele deve ver uma mensagem de erro {string}", (message: string) => {
+ cy.get(errorMessageContainer).should("contain", message);
+});
+
+Then("ele deve ser redirecionado para a página de login", () => {
+ cy.url().should("eq", Cypress.config().baseUrl + loginUrl);
+});
\ No newline at end of file
diff --git a/cypress/e2e/features/common-step-definitions/login.step.ts b/cypress/e2e/features/common-step-definitions/login.step.ts
new file mode 100644
index 00000000..8c0fc864
--- /dev/null
+++ b/cypress/e2e/features/common-step-definitions/login.step.ts
@@ -0,0 +1,62 @@
+import { Given, When, Then } from "@badeball/cypress-cucumber-preprocessor";
+
+// URL da página de login e home
+const loginUrl = "/";
+const homeUrl = "/home"; // Ajustar conforme o caminho real da sua aplicação
+const cadastroUrl = "/cadastro";
+
+// Elementos da página baseados no seu HTML
+const emailInput = 'input[type="email"][placeholder="Email"]';
+const passwordInput = 'input[type="password"][placeholder="Senha"]';
+const loginButton = 'button[type="submit"]';
+const errorMessageContainer = '.error-message'; // Ajuste para o seletor real do seu componente ErrorMessage
+const naoCadastradoLink = 'span.link:contains("Não tem conta ainda?")';
+const userInfoElement = '[data-testid="user-info"]'; // Ajuste para o seletor real onde o email do usuário é exibido
+
+// Steps para login
+Given("o usuário está na página de login", () => {
+ cy.visit(loginUrl);
+ cy.contains("Sistema de Agendamento e").should("be.visible");
+});
+
+When("ele preenche o campo de email com {string}", (email: string) => {
+ cy.get(emailInput).clear().type(email);
+});
+
+When("ele preenche o campo de senha com {string}", (password: string) => {
+ cy.get(passwordInput).clear().type(password);
+});
+
+When("ele clica no botão {string}", (buttonText: string) => {
+ cy.get(loginButton).contains(buttonText).click();
+});
+
+When("ele clica no botão {string} sem preencher os campos", (buttonText: string) => {
+ cy.get(emailInput).clear();
+ cy.get(passwordInput).clear();
+ cy.get(loginButton).contains(buttonText).click();
+});
+
+When("ele clica no link {string}", (linkText: string) => {
+ cy.contains("span.link", linkText).click();
+});
+
+Then("ele deve ser redirecionado para a página principal", () => {
+ cy.url().should("include", homeUrl);
+});
+
+Then("ele deve ver seu email {string} na tela", (email: string) => {
+ cy.get(userInfoElement).should("contain", email);
+});
+
+Then("ele deve ver uma mensagem de erro {string}", (message: string) => {
+ cy.get(errorMessageContainer).should("contain", message);
+});
+
+Then("ele deve permanecer na página de login", () => {
+ cy.url().should("eq", Cypress.config().baseUrl + loginUrl);
+});
+
+Then("ele deve ser redirecionado para a página de cadastro", () => {
+ cy.url().should("include", cadastroUrl);
+});
\ No newline at end of file
diff --git a/cypress/e2e/features/login.feature b/cypress/e2e/features/login.feature
new file mode 100644
index 00000000..fcf0c2bb
--- /dev/null
+++ b/cypress/e2e/features/login.feature
@@ -0,0 +1,28 @@
+Feature: Login de usuário no frontend
+
+ Scenario: Login bem-sucedido
+ Given o usuário está na página de login
+ When ele preenche o campo de email com "demostenes@example.com"
+ And ele preenche o campo de senha com "SecurePassword123"
+ And ele clica no botão "Entrar"
+ Then ele deve ser redirecionado para a página principal
+ And ele deve ver seu email "demostenes@example.com" na tela
+
+ Scenario: Login falha com senha incorreta
+ Given o usuário está na página de login
+ When ele preenche o campo de email com "demostenes@example.com"
+ And ele preenche o campo de senha com "SecureIncorreta123"
+ And ele clica no botão "Entrar"
+ Then ele deve ver uma mensagem de erro "Usuário ou senha inválidos."
+ And ele deve permanecer na página de login
+
+ Scenario: Login falha com campos vazios
+ Given o usuário está na página de login
+ When ele clica no botão "Entrar" sem preencher os campos
+ Then ele deve ver uma mensagem de erro "Usuário e senha são obrigatórios."
+ And ele deve permanecer na página de login
+
+ Scenario: Navegar para a página de cadastro
+ Given o usuário está na página de login
+ When ele clica no link "Não tem conta ainda?"
+ Then ele deve ser redirecionado para a página de cadastro
\ No newline at end of file
diff --git a/cypress/e2e/features/tests/ReservaSalas.feature b/cypress/e2e/features/tests/ReservaSalas.feature
new file mode 100644
index 00000000..eab391ce
--- /dev/null
+++ b/cypress/e2e/features/tests/ReservaSalas.feature
@@ -0,0 +1,14 @@
+SCENARIO: Visualizar salas de reunião disponíveis em 15/01 das 14h às 15h com ar condicionado
+ GIVEN eu estou logado como "professor" na página “Reservar"
+ AND no campo “tipo de sala” está selecionado “reunião"
+ AND no campo “data” está inserido “15/01/2025”
+ AND no campo “Hora Início” está selecionada a opção “14:00"
+ AND no campo “Hora Fim” está selecionada a opção “15:00"
+ AND no campo “Equipamentos” está selecionada a opção “Ar-condicionado"
+ WHEN eu seleciono a opção “Procurar"
+ THEN é exibida a sala "E001" como sala disponível e "bem" avaliada
+ THEN o user "aroldo@mail.com" volta á página de "login".
+
+
+SCENARIO: Sucesso ao reservar uma sala disponível
+ GIVEN
\ No newline at end of file
diff --git a/docs/cenarios.rb b/docs/cenarios.rb
new file mode 100644
index 00000000..1ff2741b
--- /dev/null
+++ b/docs/cenarios.rb
@@ -0,0 +1,86 @@
+FEATURE: Cadastrar e fazer a manutenção dos usuários
+ AS a usuário do SAGAA
+ I WANT TO cadastrar-me no novo sistema
+ SO THAT consiga acessar a plataforma
+
+
+SCENARIO: Sucesso no cadastro de usuário.
+ GIVEN eu estou na página de "Cadastro";
+ WHEN eu preencho o campo "Nome" com "Demosténes"
+ AND "CPF" com "123.456.789-00"
+ AND "Email" com "demostenes@example.com"
+ AND "Você é professor?" com "Não"
+ AND "Senha" com "SecurePassword123"
+ AND "Confirmar Senha" com "SecurePassword123";
+ AND clico em "Cadastrar";
+ THEN uma mensagem "Cadastro criado com sucesso!" deve ser exibida.
+
+
+SCENARIO: Sucesso no cadastro de professor.
+ GIVEN eu estou na página de "Cadastro";
+ WHEN eu preencho o campo "Nome" com "Paula"
+ AND "CPF" com "321.879.789-33"
+ AND "Email" com "vanessa@example.com"
+ AND "Você é professor?" com "Sim"
+ AND "SIAP" com "101010"
+ AND "Senha" com "12345678"
+ AND "Confirmar Senha" com "12345678";
+ AND clico em "Cadastrar";
+ THEN uma mensagem "Cadastro criado com sucesso!" deve ser exibida.
+
+
+
+
+SCENARIO: Fracasso no cadastro por campos obrigatórios não preenchidos
+ GIVEN eu estou na página de "Cadastro de usuário";
+ WHEN eu preencho o campo "Nome"
+ AND "CPF"
+ AND "Email"
+ AND "Você é professor?" com "Não"
+ AND "Senha"
+ AND deixo o campo "Confirmar Senha" vazio;
+ AND clico em "Cadastrar"
+ THEN uma sinalização informando que o campo "Confirmar Senha" é obrigatório deve ser exibida.
+
+
+SCENARIO: Fracasso no cadastro por duplicação de ID única.
+ GIVEN eu estou na página de "Cadastro de usuário";
+ WHEN eu preencho o campo "Nome" com "Carlos Mendes"
+ AND "CPF" com "456.123.789-10"
+ AND "Email" com "carlos.mendes@example.com"
+ AND "Você é professor?" com "Sim"
+ AND "SIAP" com "010101"
+ AND "Senha" com "Password456"
+ AND "Confirmar Senha" com "Password456";
+ AND clico em "Cadastrar";
+ THEN uma mensagem de erro "Erro: email/cpf/siap já está registrado." deve ser exibida.
+
+
+SCENARIO: Fracasso no cadastro por senhas que não coincidem
+ GIVEN eu estou na página de "Cadastro de usuário";
+ WHEN eu preencho o campo "Nome" com "Beatriz"
+ AND "CPF" com "789.456.123-00"
+ AND "Email" com "Beatriz.oliveira@example.com"
+ AND "Você é professor?" com "Não"
+ AND "Senha" com "MyPassword123"
+ AND "Confirmar Senha" com "DifferentPassword123";
+ AND clico em "Cadastrar";
+ THEN uma mensagem de erro "As senhas não coincidem." deve ser exibida.
+
+
+# Login
+SCENARIO: Sucesso no login
+GIVEN eu estou na página de "Login";
+WHEN eu preencho o campo "Email" com "demostenes@example.com"
+AND o campo "Senha" com "SecurePassword123";
+AND clico em "Entrar";
+THEN eu devo ser redirecionado para a página "reserva"
+
+
+SCENARIO: Fracasso no login
+GIVEN eu estou na página de "Login";
+WHEN eu preencho o campo "Email" com "demostenes@example.com"
+AND o campo "Senha" com "SenhaIncorreta123";
+AND clico em "Entrar";
+THEN uma sinalização de erro "Usuário ou senha incorretos." deve ser exibida.
+
diff --git a/instance/users.db b/instance/users.db
new file mode 100644
index 00000000..80b9c654
Binary files /dev/null and b/instance/users.db differ
diff --git a/package-lock.json b/package-lock.json
index 5af242dc..02b50f05 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,6 @@
},
"devDependencies": {
"@badeball/cypress-cucumber-preprocessor": "^18.0.1",
- "@bahmutov/cypress-code-coverage": "^2.6.1",
"@bahmutov/cypress-esbuild-preprocessor": "^2.2.0",
"@cucumber/cucumber": "^9.2.0",
"@cypress/code-coverage": "^3.10.7",
@@ -48,34 +47,6 @@
"vitest": "^0.31.1"
}
},
- "node_modules/@actions/core": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
- "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
- "dev": true,
- "dependencies": {
- "@actions/http-client": "^2.0.1",
- "uuid": "^8.3.2"
- }
- },
- "node_modules/@actions/core/node_modules/uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
- "dev": true,
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
- "node_modules/@actions/http-client": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz",
- "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==",
- "dev": true,
- "dependencies": {
- "tunnel": "^0.0.6"
- }
- },
"node_modules/@adobe/css-tools": {
"version": "4.2.0",
"dev": true,
@@ -167,6 +138,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@@ -178,6 +150,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@@ -215,6 +188,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
@@ -237,6 +211,7 @@
"version": "6.3.0",
"dev": true,
"license": "ISC",
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -245,6 +220,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"regexpu-core": "^5.3.1",
@@ -261,6 +237,7 @@
"version": "6.3.0",
"dev": true,
"license": "ISC",
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -269,6 +246,7 @@
"version": "0.4.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-compilation-targets": "^7.17.7",
"@babel/helper-plugin-utils": "^7.16.7",
@@ -285,6 +263,7 @@
"version": "6.3.0",
"dev": true,
"license": "ISC",
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -324,6 +303,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@@ -364,6 +344,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@@ -383,6 +364,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
@@ -400,6 +382,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-member-expression-to-functions": "^7.22.5",
@@ -427,6 +410,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@@ -473,6 +457,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-function-name": "^7.22.5",
"@babel/template": "^7.22.5",
@@ -580,6 +565,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -594,6 +580,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
@@ -610,6 +597,8 @@
"version": "7.18.6",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.18.6",
"@babel/helper-plugin-utils": "^7.18.6"
@@ -625,6 +614,8 @@
"version": "7.20.7",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/compat-data": "^7.20.5",
"@babel/helper-compilation-targets": "^7.20.7",
@@ -643,6 +634,7 @@
"version": "7.21.0-placeholder-for-preset-env.2",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=6.9.0"
},
@@ -654,6 +646,7 @@
"version": "7.18.6",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
"@babel/helper-plugin-utils": "^7.18.6"
@@ -669,6 +662,7 @@
"version": "7.8.4",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
@@ -680,6 +674,7 @@
"version": "7.12.13",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.12.13"
},
@@ -691,6 +686,7 @@
"version": "7.14.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.14.5"
},
@@ -705,6 +701,7 @@
"version": "7.8.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
@@ -716,6 +713,7 @@
"version": "7.8.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.3"
},
@@ -727,6 +725,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -741,6 +740,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -755,6 +755,7 @@
"version": "7.10.4",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.10.4"
},
@@ -766,6 +767,7 @@
"version": "7.8.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
@@ -777,6 +779,8 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -791,6 +795,7 @@
"version": "7.10.4",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.10.4"
},
@@ -802,6 +807,7 @@
"version": "7.8.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
@@ -813,6 +819,7 @@
"version": "7.10.4",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.10.4"
},
@@ -824,6 +831,7 @@
"version": "7.8.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
@@ -835,6 +843,7 @@
"version": "7.8.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
@@ -846,6 +855,7 @@
"version": "7.8.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.8.0"
},
@@ -857,6 +867,7 @@
"version": "7.14.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.14.5"
},
@@ -871,6 +882,7 @@
"version": "7.14.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.14.5"
},
@@ -885,6 +897,7 @@
"version": "7.18.6",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
"@babel/helper-plugin-utils": "^7.18.6"
@@ -900,6 +913,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -914,6 +928,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -931,6 +946,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-module-imports": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -947,6 +963,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -961,6 +978,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -975,6 +993,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -990,6 +1009,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1006,6 +1026,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5",
@@ -1028,6 +1049,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/template": "^7.22.5"
@@ -1043,6 +1065,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1057,6 +1080,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1072,6 +1096,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1086,6 +1111,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-dynamic-import": "^7.8.3"
@@ -1101,6 +1127,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1116,6 +1143,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
@@ -1131,6 +1159,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1145,6 +1174,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-compilation-targets": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
@@ -1161,6 +1191,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-json-strings": "^7.8.3"
@@ -1176,6 +1207,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1190,6 +1222,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
@@ -1205,6 +1238,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1219,6 +1253,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1234,6 +1269,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1250,6 +1286,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-module-transforms": "^7.22.5",
@@ -1267,6 +1304,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1282,6 +1320,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1297,6 +1336,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1311,6 +1351,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
@@ -1326,6 +1367,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-numeric-separator": "^7.10.4"
@@ -1341,6 +1383,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/compat-data": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5",
@@ -1359,6 +1402,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-replace-supers": "^7.22.5"
@@ -1374,6 +1418,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
@@ -1389,6 +1434,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
@@ -1405,6 +1451,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1419,6 +1466,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1434,6 +1482,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-create-class-features-plugin": "^7.22.5",
@@ -1451,6 +1500,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1465,6 +1515,8 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1479,6 +1531,8 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-module-imports": "^7.22.5",
@@ -1497,6 +1551,8 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/plugin-transform-react-jsx": "^7.22.5"
},
@@ -1539,6 +1595,8 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1554,6 +1612,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"regenerator-transform": "^0.15.1"
@@ -1569,6 +1628,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1583,6 +1643,8 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/helper-module-imports": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1602,6 +1664,8 @@
"version": "6.3.0",
"dev": true,
"license": "ISC",
+ "optional": true,
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -1610,6 +1674,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1624,6 +1689,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
@@ -1639,6 +1705,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1653,6 +1720,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1667,6 +1735,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1681,6 +1750,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1695,6 +1765,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1710,6 +1781,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1725,6 +1797,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1740,6 +1813,7 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/compat-data": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5",
@@ -1833,6 +1907,7 @@
"version": "6.3.0",
"dev": true,
"license": "ISC",
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -1841,6 +1916,7 @@
"version": "0.1.5",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
@@ -1856,6 +1932,8 @@
"version": "7.22.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-validator-option": "^7.22.5",
@@ -1874,7 +1952,8 @@
"node_modules/@babel/regjsgen": {
"version": "0.8.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@babel/runtime": {
"version": "7.22.5",
@@ -2202,161 +2281,6 @@
"node": "*"
}
},
- "node_modules/@bahmutov/cypress-code-coverage": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/@bahmutov/cypress-code-coverage/-/cypress-code-coverage-2.6.1.tgz",
- "integrity": "sha512-oK6RP+537hcIB90QdI4m/u95Pr7YYgbD4PwoDJr924t6viiN8hSc1f3BbD5D8Xuq9JagXLes68l7+lR0cBI9Hg==",
- "dev": true,
- "dependencies": {
- "@actions/core": "^1.10.0",
- "@cypress/browserify-preprocessor": "3.0.2",
- "chalk": "4.1.2",
- "console.table": "^0.10.0",
- "dayjs": "1.10.7",
- "debug": "4.3.3",
- "execa": "4.1.0",
- "globby": "11.1.0",
- "istanbul-lib-coverage": "3.0.0",
- "js-yaml": "3.14.1",
- "nyc": "15.1.0",
- "rimraf": "^4.4.1",
- "sort-array": "^4.1.5"
- },
- "bin": {
- "cc-merge": "bin/cc-merge.js"
- },
- "peerDependencies": {
- "cypress": ">=10.0.0"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/debug": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
- "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/glob": {
- "version": "9.3.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
- "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "minimatch": "^8.0.2",
- "minipass": "^4.2.4",
- "path-scurry": "^1.6.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/minimatch": {
- "version": "8.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
- "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/minipass": {
- "version": "4.2.8",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
- "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@bahmutov/cypress-code-coverage/node_modules/rimraf": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz",
- "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==",
- "dev": true,
- "dependencies": {
- "glob": "^9.2.0"
- },
- "bin": {
- "rimraf": "dist/cjs/src/bin.js"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/@bahmutov/cypress-esbuild-preprocessor": {
"version": "2.2.0",
"dev": true,
@@ -2590,6 +2514,8 @@
"version": "3.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"@babel/core": "^7.16.0",
"@babel/plugin-proposal-class-properties": "^7.16.0",
@@ -4054,6 +3980,8 @@
"version": "1.8.2",
"dev": true,
"license": "Apache-2.0",
+ "optional": true,
+ "peer": true,
"dependencies": {
"acorn": "^7.0.0",
"acorn-walk": "^7.0.0",
@@ -4064,6 +3992,8 @@
"version": "7.4.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -4075,6 +4005,8 @@
"version": "7.2.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.4.0"
}
@@ -4279,15 +4211,6 @@
"dequal": "^2.0.3"
}
},
- "node_modules/array-back": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz",
- "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/array-buffer-byte-length": {
"version": "1.0.0",
"dev": true,
@@ -4320,6 +4243,8 @@
"version": "5.4.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^4.0.0",
"inherits": "^2.0.1",
@@ -4330,12 +4255,16 @@
"node_modules/asn1.js/node_modules/bn.js": {
"version": "4.12.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/assert": {
"version": "1.5.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"object-assign": "^4.1.1",
"util": "0.10.3"
@@ -4352,12 +4281,16 @@
"node_modules/assert/node_modules/inherits": {
"version": "2.0.1",
"dev": true,
- "license": "ISC"
- },
- "node_modules/assert/node_modules/util": {
+ "license": "ISC",
+ "optional": true,
+ "peer": true
+ },
+ "node_modules/assert/node_modules/util": {
"version": "0.10.3",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "2.0.1"
}
@@ -4458,12 +4391,15 @@
"node_modules/babel-plugin-add-module-exports": {
"version": "1.0.4",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.3",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/compat-data": "^7.17.7",
"@babel/helper-define-polyfill-provider": "^0.4.0",
@@ -4477,6 +4413,7 @@
"version": "6.3.0",
"dev": true,
"license": "ISC",
+ "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -4485,6 +4422,7 @@
"version": "0.8.1",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.4.0",
"core-js-compat": "^3.30.1"
@@ -4497,6 +4435,7 @@
"version": "0.5.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.4.0"
},
@@ -4508,6 +4447,8 @@
"version": "10.0.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=6.9.0"
},
@@ -4573,7 +4514,9 @@
"node_modules/bn.js": {
"version": "5.2.1",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
@@ -4598,12 +4541,16 @@
"node_modules/brorand": {
"version": "1.1.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/browser-pack": {
"version": "6.1.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"combine-source-map": "~0.8.0",
"defined": "^1.0.0",
@@ -4620,6 +4567,8 @@
"version": "2.0.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"resolve": "^1.17.0"
}
@@ -4633,6 +4582,8 @@
"version": "16.5.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"assert": "^1.4.0",
"browser-pack": "^6.0.1",
@@ -4694,6 +4645,8 @@
"version": "1.2.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0",
@@ -4707,6 +4660,8 @@
"version": "1.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"browserify-aes": "^1.0.4",
"browserify-des": "^1.0.0",
@@ -4717,6 +4672,8 @@
"version": "1.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"cipher-base": "^1.0.1",
"des.js": "^1.0.0",
@@ -4728,6 +4685,8 @@
"version": "4.1.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^5.0.0",
"randombytes": "^2.0.1"
@@ -4737,6 +4696,8 @@
"version": "4.2.1",
"dev": true,
"license": "ISC",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^5.1.1",
"browserify-rsa": "^4.0.1",
@@ -4753,6 +4714,8 @@
"version": "3.6.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -4766,6 +4729,8 @@
"version": "0.2.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"pako": "~1.0.5"
}
@@ -4805,6 +4770,8 @@
"version": "5.2.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
@@ -4826,12 +4793,16 @@
"node_modules/buffer-xor": {
"version": "1.0.3",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/builtin-status-codes": {
"version": "3.0.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/c8": {
"version": "7.14.0",
@@ -4877,7 +4848,9 @@
"node_modules/cached-path-relative": {
"version": "1.1.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/cachedir": {
"version": "2.3.0",
@@ -5026,6 +4999,8 @@
"version": "3.5.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -5069,6 +5044,8 @@
"version": "1.0.4",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -5155,20 +5132,12 @@
"wrap-ansi": "^7.0.0"
}
},
- "node_modules/clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=0.8"
- }
- },
"node_modules/coffeeify": {
"version": "3.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"convert-source-map": "^1.3.0",
"through2": "^2.0.0"
@@ -5181,6 +5150,8 @@
"version": "1.12.7",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"bin": {
"cake": "bin/cake",
"coffee": "bin/coffee"
@@ -5214,6 +5185,8 @@
"version": "0.8.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"convert-source-map": "~1.1.0",
"inline-source-map": "~0.6.0",
@@ -5224,7 +5197,9 @@
"node_modules/combine-source-map/node_modules/convert-source-map": {
"version": "1.1.3",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
@@ -5274,6 +5249,8 @@
"node >= 0.8"
],
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
@@ -5301,24 +5278,16 @@
},
"node_modules/console-browserify": {
"version": "1.2.0",
- "dev": true
- },
- "node_modules/console.table": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz",
- "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==",
"dev": true,
- "dependencies": {
- "easy-table": "1.1.0"
- },
- "engines": {
- "node": "> 0.10"
- }
+ "optional": true,
+ "peer": true
},
"node_modules/constants-browserify": {
"version": "1.0.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/convert-source-map": {
"version": "1.9.0",
@@ -5329,6 +5298,7 @@
"version": "3.31.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"browserslist": "^4.21.5"
},
@@ -5340,12 +5310,16 @@
"node_modules/core-util-is": {
"version": "1.0.3",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/create-ecdh": {
"version": "4.0.4",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^4.1.0",
"elliptic": "^6.5.3"
@@ -5354,12 +5328,16 @@
"node_modules/create-ecdh/node_modules/bn.js": {
"version": "4.12.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/create-hash": {
"version": "1.2.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
@@ -5372,6 +5350,8 @@
"version": "1.1.7",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
@@ -5398,6 +5378,8 @@
"version": "3.12.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"browserify-cipher": "^1.0.0",
"browserify-sign": "^4.0.0",
@@ -5536,7 +5518,9 @@
"node_modules/dash-ast": {
"version": "1.0.0",
"dev": true,
- "license": "Apache-2.0"
+ "license": "Apache-2.0",
+ "optional": true,
+ "peer": true
},
"node_modules/dashdash": {
"version": "1.14.1",
@@ -5670,19 +5654,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/defaults": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
- "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "clone": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/define-properties": {
"version": "1.2.0",
"dev": true,
@@ -5702,6 +5673,8 @@
"version": "1.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -5717,6 +5690,8 @@
"version": "2.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"JSONStream": "^1.0.3",
"shasum-object": "^1.0.0",
@@ -5739,6 +5714,8 @@
"version": "1.1.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0"
@@ -5748,6 +5725,8 @@
"version": "5.2.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"acorn-node": "^1.8.2",
"defined": "^1.0.0",
@@ -5780,6 +5759,8 @@
"version": "5.0.3",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^4.1.0",
"miller-rabin": "^4.0.0",
@@ -5789,7 +5770,9 @@
"node_modules/diffie-hellman/node_modules/bn.js": {
"version": "4.12.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/dir-glob": {
"version": "3.0.1",
@@ -5822,6 +5805,8 @@
"version": "1.2.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.4",
"npm": ">=1.2"
@@ -5847,6 +5832,8 @@
"version": "0.1.4",
"dev": true,
"license": "BSD-3-Clause",
+ "optional": true,
+ "peer": true,
"dependencies": {
"readable-stream": "^2.0.2"
}
@@ -5856,15 +5843,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/easy-table": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz",
- "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==",
- "dev": true,
- "optionalDependencies": {
- "wcwidth": ">=1.0.1"
- }
- },
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"dev": true,
@@ -5883,6 +5861,8 @@
"version": "6.5.4",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
@@ -5896,7 +5876,9 @@
"node_modules/elliptic/node_modules/bn.js": {
"version": "4.12.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/emoji-regex": {
"version": "8.0.0",
@@ -6336,6 +6318,8 @@
"version": "2.1.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.4.x"
}
@@ -6344,6 +6328,8 @@
"version": "1.0.3",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"md5.js": "^1.3.4",
"safe-buffer": "^5.1.1"
@@ -6467,7 +6453,9 @@
"node_modules/fast-safe-stringify": {
"version": "2.1.1",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/fastq": {
"version": "1.15.0",
@@ -6714,7 +6702,9 @@
"node_modules/get-assigned-identifiers": {
"version": "1.2.0",
"dev": true,
- "license": "Apache-2.0"
+ "license": "Apache-2.0",
+ "optional": true,
+ "peer": true
},
"node_modules/get-caller-file": {
"version": "2.0.5",
@@ -6976,6 +6966,8 @@
"version": "3.1.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
@@ -6989,6 +6981,8 @@
"version": "3.6.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -7002,6 +6996,8 @@
"version": "1.1.7",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
@@ -7042,6 +7038,8 @@
"version": "1.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
@@ -7068,6 +7066,8 @@
"version": "1.1.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.10"
}
@@ -7101,7 +7101,9 @@
"node_modules/https-browserify": {
"version": "1.0.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/https-proxy-agent": {
"version": "5.0.1",
@@ -7232,6 +7234,8 @@
"version": "0.6.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"source-map": "~0.5.3"
}
@@ -7240,6 +7244,8 @@
"version": "7.2.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"acorn-node": "^1.5.2",
"combine-source-map": "^0.8.0",
@@ -7342,7 +7348,9 @@
"node_modules/is-buffer": {
"version": "1.1.6",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/is-callable": {
"version": "1.2.7",
@@ -7370,6 +7378,7 @@
"version": "2.12.1",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"has": "^1.0.3"
},
@@ -7411,6 +7420,8 @@
"version": "1.0.10",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
@@ -7636,7 +7647,9 @@
"node_modules/isarray": {
"version": "1.0.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/isexe": {
"version": "2.0.0",
@@ -8119,6 +8132,8 @@
"version": "0.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"jsonify": "~0.0.0"
}
@@ -8164,6 +8179,8 @@
"version": "0.0.1",
"dev": true,
"license": "Public Domain",
+ "optional": true,
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -8174,12 +8191,16 @@
"engines": [
"node >= 0.2.0"
],
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/JSONStream": {
"version": "1.3.5",
"dev": true,
"license": "(MIT OR Apache-2.0)",
+ "optional": true,
+ "peer": true,
"dependencies": {
"jsonparse": "^1.2.0",
"through": ">=2.2.7 <3"
@@ -8235,6 +8256,8 @@
"version": "2.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.1",
"stream-splicer": "^2.0.0"
@@ -8338,12 +8361,15 @@
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/lodash.flattendeep": {
"version": "4.4.0",
@@ -8353,7 +8379,9 @@
"node_modules/lodash.memoize": {
"version": "3.0.4",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@@ -8533,6 +8561,8 @@
"version": "1.3.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
@@ -8568,6 +8598,8 @@
"version": "4.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^4.0.0",
"brorand": "^1.0.1"
@@ -8579,7 +8611,9 @@
"node_modules/miller-rabin/node_modules/bn.js": {
"version": "4.12.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/mime-db": {
"version": "1.52.0",
@@ -8617,12 +8651,16 @@
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"dev": true,
- "license": "ISC"
+ "license": "ISC",
+ "optional": true,
+ "peer": true
},
"node_modules/minimalistic-crypto-utils": {
"version": "1.0.1",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/minimatch": {
"version": "3.1.2",
@@ -8668,7 +8706,9 @@
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/mlly": {
"version": "1.4.0",
@@ -8858,6 +8898,8 @@
"version": "6.2.3",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"browser-resolve": "^2.0.0",
"cached-path-relative": "^1.0.2",
@@ -9254,7 +9296,9 @@
"node_modules/os-browserify": {
"version": "0.3.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/ospath": {
"version": "1.2.2",
@@ -9265,6 +9309,8 @@
"version": "1.1.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"shell-quote": "^1.4.2"
}
@@ -9347,7 +9393,9 @@
"node_modules/pako": {
"version": "1.0.11",
"dev": true,
- "license": "(MIT AND Zlib)"
+ "license": "(MIT AND Zlib)",
+ "optional": true,
+ "peer": true
},
"node_modules/parent-module": {
"version": "1.0.1",
@@ -9364,6 +9412,8 @@
"version": "1.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"path-platform": "~0.11.15"
}
@@ -9372,6 +9422,8 @@
"version": "5.1.6",
"dev": true,
"license": "ISC",
+ "optional": true,
+ "peer": true,
"dependencies": {
"asn1.js": "^5.2.0",
"browserify-aes": "^1.0.0",
@@ -9394,7 +9446,9 @@
"node_modules/path-browserify": {
"version": "0.0.1",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/path-exists": {
"version": "4.0.0",
@@ -9423,12 +9477,15 @@
"node_modules/path-parse": {
"version": "1.0.7",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/path-platform": {
"version": "0.11.15",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">= 0.8.0"
}
@@ -9492,6 +9549,8 @@
"version": "3.1.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
@@ -9688,6 +9747,8 @@
"version": "0.11.10",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">= 0.6.0"
}
@@ -9695,7 +9756,9 @@
"node_modules/process-nextick-args": {
"version": "2.0.1",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/process-on-spawn": {
"version": "1.0.0",
@@ -9748,6 +9811,8 @@
"version": "4.0.3",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"bn.js": "^4.1.0",
"browserify-rsa": "^4.0.0",
@@ -9760,7 +9825,9 @@
"node_modules/public-encrypt/node_modules/bn.js": {
"version": "4.12.0",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/pump": {
"version": "3.0.0",
@@ -9774,7 +9841,9 @@
"node_modules/punycode": {
"version": "1.4.1",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/qs": {
"version": "6.10.4",
@@ -9793,6 +9862,8 @@
"node_modules/querystring-es3": {
"version": "0.2.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.4.x"
}
@@ -9833,6 +9904,8 @@
"version": "1.0.4",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"randombytes": "^2.0.5",
"safe-buffer": "^5.1.0"
@@ -9918,6 +9991,8 @@
"version": "2.0.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"readable-stream": "^2.0.2"
}
@@ -9926,6 +10001,8 @@
"version": "2.3.8",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -9939,12 +10016,16 @@
"node_modules/readable-stream/node_modules/safe-buffer": {
"version": "5.1.2",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/readable-stream/node_modules/string_decoder": {
"version": "1.1.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"safe-buffer": "~5.1.0"
}
@@ -9980,12 +10061,14 @@
"node_modules/regenerate": {
"version": "1.4.2",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/regenerate-unicode-properties": {
"version": "10.1.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"regenerate": "^1.4.2"
},
@@ -10002,6 +10085,7 @@
"version": "0.15.1",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.8.4"
}
@@ -10042,6 +10126,7 @@
"version": "5.3.2",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/regjsgen": "^0.8.0",
"regenerate": "^1.4.2",
@@ -10058,6 +10143,7 @@
"version": "0.9.1",
"dev": true,
"license": "BSD-2-Clause",
+ "peer": true,
"dependencies": {
"jsesc": "~0.5.0"
},
@@ -10068,6 +10154,7 @@
"node_modules/regjsparser/node_modules/jsesc": {
"version": "0.5.0",
"dev": true,
+ "peer": true,
"bin": {
"jsesc": "bin/jsesc"
}
@@ -10130,6 +10217,7 @@
"version": "1.22.2",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
@@ -10213,6 +10301,8 @@
"version": "2.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
@@ -10421,6 +10511,8 @@
"version": "2.4.11",
"dev": true,
"license": "(MIT AND BSD-3-Clause)",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -10433,6 +10525,8 @@
"version": "1.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"json-stable-stringify": "~0.0.0",
"sha.js": "~2.4.4"
@@ -10442,6 +10536,8 @@
"version": "1.0.0",
"dev": true,
"license": "Apache-2.0",
+ "optional": true,
+ "peer": true,
"dependencies": {
"fast-safe-stringify": "^2.0.7"
}
@@ -10469,6 +10565,8 @@
"version": "1.8.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -10513,7 +10611,9 @@
"url": "https://feross.org/support"
}
],
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/slash": {
"version": "3.0.0",
@@ -10536,23 +10636,12 @@
"node": ">=8"
}
},
- "node_modules/sort-array": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.5.tgz",
- "integrity": "sha512-Ya4peoS1fgFN42RN1REk2FgdNOeLIEMKFGJvs7VTP3OklF8+kl2SkpVliZ4tk/PurWsrWRsdNdU+tgyOBkB9sA==",
- "dev": true,
- "dependencies": {
- "array-back": "^5.0.0",
- "typical": "^6.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/source-map": {
"version": "0.5.7",
"dev": true,
"license": "BSD-3-Clause",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -10751,6 +10840,8 @@
"version": "2.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "~2.0.1",
"readable-stream": "^2.0.2"
@@ -10768,6 +10859,8 @@
"version": "1.1.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"duplexer2": "~0.1.0",
"readable-stream": "^2.0.2"
@@ -10777,6 +10870,8 @@
"version": "3.2.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"builtin-status-codes": "^3.0.0",
"inherits": "^2.0.4",
@@ -10788,6 +10883,8 @@
"version": "3.6.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -10801,6 +10898,8 @@
"version": "2.0.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.1",
"readable-stream": "^2.0.2"
@@ -10810,6 +10909,8 @@
"version": "1.3.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
@@ -10941,6 +11042,8 @@
"version": "1.0.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"minimist": "^1.1.0"
}
@@ -10963,6 +11066,7 @@
"version": "1.0.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">= 0.4"
},
@@ -10979,6 +11083,8 @@
"version": "1.4.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"acorn-node": "^1.2.0"
}
@@ -11119,6 +11225,8 @@
"version": "2.0.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
@@ -11135,6 +11243,8 @@
"node_modules/timers-browserify": {
"version": "1.4.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"dependencies": {
"process": "~0.11.0"
},
@@ -11272,16 +11382,9 @@
"node_modules/tty-browserify": {
"version": "0.0.1",
"dev": true,
- "license": "MIT"
- },
- "node_modules/tunnel": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
- "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
- "dev": true,
- "engines": {
- "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
- }
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
@@ -11332,7 +11435,9 @@
"node_modules/typedarray": {
"version": "0.0.6",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/typedarray-to-buffer": {
"version": "3.1.5",
@@ -11354,15 +11459,6 @@
"node": ">=14.17"
}
},
- "node_modules/typical": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/typical/-/typical-6.0.1.tgz",
- "integrity": "sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/ufo": {
"version": "1.1.2",
"dev": true,
@@ -11372,6 +11468,8 @@
"version": "3.0.3",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"bin": {
"umd": "bin/cli.js"
}
@@ -11380,6 +11478,8 @@
"version": "1.1.3",
"dev": true,
"license": "Apache-2.0",
+ "optional": true,
+ "peer": true,
"dependencies": {
"acorn-node": "^1.3.0",
"dash-ast": "^1.0.0",
@@ -11395,6 +11495,7 @@
"version": "2.0.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -11403,6 +11504,7 @@
"version": "2.0.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"unicode-canonical-property-names-ecmascript": "^2.0.0",
"unicode-property-aliases-ecmascript": "^2.0.0"
@@ -11415,6 +11517,7 @@
"version": "2.1.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -11423,6 +11526,7 @@
"version": "2.1.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=4"
}
@@ -11500,6 +11604,8 @@
"version": "0.11.1",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"punycode": "^1.4.1",
"qs": "^6.11.0"
@@ -11518,6 +11624,8 @@
"version": "6.11.2",
"dev": true,
"license": "BSD-3-Clause",
+ "optional": true,
+ "peer": true,
"dependencies": {
"side-channel": "^1.0.4"
},
@@ -11532,6 +11640,8 @@
"version": "0.10.4",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "2.0.3"
}
@@ -11544,12 +11654,16 @@
"node_modules/util-deprecate": {
"version": "1.0.2",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/util/node_modules/inherits": {
"version": "2.0.3",
"dev": true,
- "license": "ISC"
+ "license": "ISC",
+ "optional": true,
+ "peer": true
},
"node_modules/uuid": {
"version": "9.0.0",
@@ -11843,7 +11957,9 @@
"node_modules/vm-browserify": {
"version": "1.1.2",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
@@ -11887,6 +12003,8 @@
"version": "4.0.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"anymatch": "^3.1.0",
"browserify": "^17.0.0",
@@ -11907,6 +12025,8 @@
"version": "17.0.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"assert": "^1.4.0",
"browser-pack": "^6.0.1",
@@ -11968,6 +12088,8 @@
"version": "2.0.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
@@ -11977,6 +12099,8 @@
"version": "3.3.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.8.x"
}
@@ -11984,12 +12108,16 @@
"node_modules/watchify/node_modules/path-browserify": {
"version": "1.0.1",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "optional": true,
+ "peer": true
},
"node_modules/watchify/node_modules/stream-browserify": {
"version": "3.0.0",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
@@ -11999,6 +12127,8 @@
"version": "3.6.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -12012,6 +12142,8 @@
"version": "4.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"readable-stream": "3"
}
@@ -12020,6 +12152,8 @@
"version": "3.6.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -12033,6 +12167,8 @@
"version": "0.12.5",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"dependencies": {
"inherits": "^2.0.3",
"is-arguments": "^1.0.4",
@@ -12054,16 +12190,6 @@
"node": ">=10.13.0"
}
},
- "node_modules/wcwidth": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
- "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "defaults": "^1.0.3"
- }
- },
"node_modules/webidl-conversions": {
"version": "7.0.0",
"dev": true,
@@ -12383,6 +12509,8 @@
"version": "4.0.2",
"dev": true,
"license": "MIT",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.4"
}
@@ -12515,33 +12643,6 @@
}
},
"dependencies": {
- "@actions/core": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
- "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
- "dev": true,
- "requires": {
- "@actions/http-client": "^2.0.1",
- "uuid": "^8.3.2"
- },
- "dependencies": {
- "uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
- "dev": true
- }
- }
- },
- "@actions/http-client": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz",
- "integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==",
- "dev": true,
- "requires": {
- "tunnel": "^0.0.6"
- }
- },
"@adobe/css-tools": {
"version": "4.2.0",
"dev": true
@@ -12605,6 +12706,7 @@
"@babel/helper-annotate-as-pure": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/types": "^7.22.5"
}
@@ -12612,6 +12714,7 @@
"@babel/helper-builder-binary-assignment-operator-visitor": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/types": "^7.22.5"
}
@@ -12636,6 +12739,7 @@
"@babel/helper-create-class-features-plugin": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
@@ -12650,13 +12754,15 @@
"dependencies": {
"semver": {
"version": "6.3.0",
- "dev": true
+ "dev": true,
+ "peer": true
}
}
},
"@babel/helper-create-regexp-features-plugin": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"regexpu-core": "^5.3.1",
@@ -12665,13 +12771,15 @@
"dependencies": {
"semver": {
"version": "6.3.0",
- "dev": true
+ "dev": true,
+ "peer": true
}
}
},
"@babel/helper-define-polyfill-provider": {
"version": "0.4.0",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-compilation-targets": "^7.17.7",
"@babel/helper-plugin-utils": "^7.16.7",
@@ -12683,7 +12791,8 @@
"dependencies": {
"semver": {
"version": "6.3.0",
- "dev": true
+ "dev": true,
+ "peer": true
}
}
},
@@ -12709,6 +12818,7 @@
"@babel/helper-member-expression-to-functions": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/types": "^7.22.5"
}
@@ -12737,6 +12847,7 @@
"@babel/helper-optimise-call-expression": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/types": "^7.22.5"
}
@@ -12748,6 +12859,7 @@
"@babel/helper-remap-async-to-generator": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
@@ -12758,6 +12870,7 @@
"@babel/helper-replace-supers": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-member-expression-to-functions": "^7.22.5",
@@ -12777,6 +12890,7 @@
"@babel/helper-skip-transparent-expression-wrappers": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/types": "^7.22.5"
}
@@ -12803,6 +12917,7 @@
"@babel/helper-wrap-function": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-function-name": "^7.22.5",
"@babel/template": "^7.22.5",
@@ -12875,6 +12990,7 @@
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -12882,6 +12998,7 @@
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
@@ -12891,6 +13008,8 @@
"@babel/plugin-proposal-class-properties": {
"version": "7.18.6",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/helper-create-class-features-plugin": "^7.18.6",
"@babel/helper-plugin-utils": "^7.18.6"
@@ -12899,6 +13018,8 @@
"@babel/plugin-proposal-object-rest-spread": {
"version": "7.20.7",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/compat-data": "^7.20.5",
"@babel/helper-compilation-targets": "^7.20.7",
@@ -12910,11 +13031,13 @@
"@babel/plugin-proposal-private-property-in-object": {
"version": "7.21.0-placeholder-for-preset-env.2",
"dev": true,
+ "peer": true,
"requires": {}
},
"@babel/plugin-proposal-unicode-property-regex": {
"version": "7.18.6",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
"@babel/helper-plugin-utils": "^7.18.6"
@@ -12923,6 +13046,7 @@
"@babel/plugin-syntax-async-generators": {
"version": "7.8.4",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.0"
}
@@ -12930,6 +13054,7 @@
"@babel/plugin-syntax-class-properties": {
"version": "7.12.13",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.12.13"
}
@@ -12937,6 +13062,7 @@
"@babel/plugin-syntax-class-static-block": {
"version": "7.14.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.14.5"
}
@@ -12944,6 +13070,7 @@
"@babel/plugin-syntax-dynamic-import": {
"version": "7.8.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.0"
}
@@ -12951,6 +13078,7 @@
"@babel/plugin-syntax-export-namespace-from": {
"version": "7.8.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.3"
}
@@ -12958,6 +13086,7 @@
"@babel/plugin-syntax-import-assertions": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -12965,6 +13094,7 @@
"@babel/plugin-syntax-import-attributes": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -12972,6 +13102,7 @@
"@babel/plugin-syntax-import-meta": {
"version": "7.10.4",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
@@ -12979,6 +13110,7 @@
"@babel/plugin-syntax-json-strings": {
"version": "7.8.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.0"
}
@@ -12986,6 +13118,8 @@
"@babel/plugin-syntax-jsx": {
"version": "7.22.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -12993,6 +13127,7 @@
"@babel/plugin-syntax-logical-assignment-operators": {
"version": "7.10.4",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
@@ -13000,6 +13135,7 @@
"@babel/plugin-syntax-nullish-coalescing-operator": {
"version": "7.8.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.0"
}
@@ -13007,6 +13143,7 @@
"@babel/plugin-syntax-numeric-separator": {
"version": "7.10.4",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.10.4"
}
@@ -13014,6 +13151,7 @@
"@babel/plugin-syntax-object-rest-spread": {
"version": "7.8.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.0"
}
@@ -13021,6 +13159,7 @@
"@babel/plugin-syntax-optional-catch-binding": {
"version": "7.8.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.0"
}
@@ -13028,6 +13167,7 @@
"@babel/plugin-syntax-optional-chaining": {
"version": "7.8.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.0"
}
@@ -13035,6 +13175,7 @@
"@babel/plugin-syntax-private-property-in-object": {
"version": "7.14.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.14.5"
}
@@ -13042,6 +13183,7 @@
"@babel/plugin-syntax-top-level-await": {
"version": "7.14.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.14.5"
}
@@ -13049,6 +13191,7 @@
"@babel/plugin-syntax-unicode-sets-regex": {
"version": "7.18.6",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
"@babel/helper-plugin-utils": "^7.18.6"
@@ -13057,6 +13200,7 @@
"@babel/plugin-transform-arrow-functions": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13064,6 +13208,7 @@
"@babel/plugin-transform-async-generator-functions": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -13074,6 +13219,7 @@
"@babel/plugin-transform-async-to-generator": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-module-imports": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -13083,6 +13229,7 @@
"@babel/plugin-transform-block-scoped-functions": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13090,6 +13237,7 @@
"@babel/plugin-transform-block-scoping": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13097,6 +13245,7 @@
"@babel/plugin-transform-class-properties": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-class-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13105,6 +13254,7 @@
"@babel/plugin-transform-class-static-block": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-class-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -13114,6 +13264,7 @@
"@babel/plugin-transform-classes": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5",
@@ -13129,6 +13280,7 @@
"@babel/plugin-transform-computed-properties": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/template": "^7.22.5"
@@ -13137,6 +13289,7 @@
"@babel/plugin-transform-destructuring": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13144,6 +13297,7 @@
"@babel/plugin-transform-dotall-regex": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13152,6 +13306,7 @@
"@babel/plugin-transform-duplicate-keys": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13159,6 +13314,7 @@
"@babel/plugin-transform-dynamic-import": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-dynamic-import": "^7.8.3"
@@ -13167,6 +13323,7 @@
"@babel/plugin-transform-exponentiation-operator": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13175,6 +13332,7 @@
"@babel/plugin-transform-export-namespace-from": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
@@ -13183,6 +13341,7 @@
"@babel/plugin-transform-for-of": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13190,6 +13349,7 @@
"@babel/plugin-transform-function-name": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-compilation-targets": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
@@ -13199,6 +13359,7 @@
"@babel/plugin-transform-json-strings": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-json-strings": "^7.8.3"
@@ -13207,6 +13368,7 @@
"@babel/plugin-transform-literals": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13214,6 +13376,7 @@
"@babel/plugin-transform-logical-assignment-operators": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
@@ -13222,6 +13385,7 @@
"@babel/plugin-transform-member-expression-literals": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13229,6 +13393,7 @@
"@babel/plugin-transform-modules-amd": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-module-transforms": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13237,6 +13402,7 @@
"@babel/plugin-transform-modules-commonjs": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-module-transforms": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -13246,6 +13412,7 @@
"@babel/plugin-transform-modules-systemjs": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-module-transforms": "^7.22.5",
@@ -13256,6 +13423,7 @@
"@babel/plugin-transform-modules-umd": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-module-transforms": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13264,6 +13432,7 @@
"@babel/plugin-transform-named-capturing-groups-regex": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13272,6 +13441,7 @@
"@babel/plugin-transform-new-target": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13279,6 +13449,7 @@
"@babel/plugin-transform-nullish-coalescing-operator": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
@@ -13287,6 +13458,7 @@
"@babel/plugin-transform-numeric-separator": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-numeric-separator": "^7.10.4"
@@ -13295,6 +13467,7 @@
"@babel/plugin-transform-object-rest-spread": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/compat-data": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5",
@@ -13306,6 +13479,7 @@
"@babel/plugin-transform-object-super": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-replace-supers": "^7.22.5"
@@ -13314,6 +13488,7 @@
"@babel/plugin-transform-optional-catch-binding": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
@@ -13322,6 +13497,7 @@
"@babel/plugin-transform-optional-chaining": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
@@ -13331,6 +13507,7 @@
"@babel/plugin-transform-parameters": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13338,6 +13515,7 @@
"@babel/plugin-transform-private-methods": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-class-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13346,6 +13524,7 @@
"@babel/plugin-transform-private-property-in-object": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-create-class-features-plugin": "^7.22.5",
@@ -13356,6 +13535,7 @@
"@babel/plugin-transform-property-literals": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13363,6 +13543,8 @@
"@babel/plugin-transform-react-display-name": {
"version": "7.22.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13370,6 +13552,8 @@
"@babel/plugin-transform-react-jsx": {
"version": "7.22.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-module-imports": "^7.22.5",
@@ -13381,6 +13565,8 @@
"@babel/plugin-transform-react-jsx-development": {
"version": "7.22.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/plugin-transform-react-jsx": "^7.22.5"
}
@@ -13402,6 +13588,8 @@
"@babel/plugin-transform-react-pure-annotations": {
"version": "7.22.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13410,6 +13598,7 @@
"@babel/plugin-transform-regenerator": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"regenerator-transform": "^0.15.1"
@@ -13418,6 +13607,7 @@
"@babel/plugin-transform-reserved-words": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13425,6 +13615,8 @@
"@babel/plugin-transform-runtime": {
"version": "7.22.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/helper-module-imports": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
@@ -13436,13 +13628,16 @@
"dependencies": {
"semver": {
"version": "6.3.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
"@babel/plugin-transform-shorthand-properties": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13450,6 +13645,7 @@
"@babel/plugin-transform-spread": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
@@ -13458,6 +13654,7 @@
"@babel/plugin-transform-sticky-regex": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13465,6 +13662,7 @@
"@babel/plugin-transform-template-literals": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13472,6 +13670,7 @@
"@babel/plugin-transform-typeof-symbol": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13479,6 +13678,7 @@
"@babel/plugin-transform-unicode-escapes": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -13486,6 +13686,7 @@
"@babel/plugin-transform-unicode-property-regex": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13494,6 +13695,7 @@
"@babel/plugin-transform-unicode-regex": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13502,6 +13704,7 @@
"@babel/plugin-transform-unicode-sets-regex": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5"
@@ -13510,6 +13713,7 @@
"@babel/preset-env": {
"version": "7.22.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/compat-data": "^7.22.5",
"@babel/helper-compilation-targets": "^7.22.5",
@@ -13595,13 +13799,15 @@
"dependencies": {
"semver": {
"version": "6.3.0",
- "dev": true
+ "dev": true,
+ "peer": true
}
}
},
"@babel/preset-modules": {
"version": "0.1.5",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
@@ -13613,6 +13819,8 @@
"@babel/preset-react": {
"version": "7.22.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-validator-option": "^7.22.5",
@@ -13624,7 +13832,8 @@
},
"@babel/regjsgen": {
"version": "0.8.0",
- "dev": true
+ "dev": true,
+ "peer": true
},
"@babel/runtime": {
"version": "7.22.5",
@@ -13841,116 +14050,6 @@
}
}
},
- "@bahmutov/cypress-code-coverage": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/@bahmutov/cypress-code-coverage/-/cypress-code-coverage-2.6.1.tgz",
- "integrity": "sha512-oK6RP+537hcIB90QdI4m/u95Pr7YYgbD4PwoDJr924t6viiN8hSc1f3BbD5D8Xuq9JagXLes68l7+lR0cBI9Hg==",
- "dev": true,
- "requires": {
- "@actions/core": "^1.10.0",
- "@cypress/browserify-preprocessor": "3.0.2",
- "chalk": "4.1.2",
- "console.table": "^0.10.0",
- "dayjs": "1.10.7",
- "debug": "4.3.3",
- "execa": "4.1.0",
- "globby": "11.1.0",
- "istanbul-lib-coverage": "3.0.0",
- "js-yaml": "3.14.1",
- "nyc": "15.1.0",
- "rimraf": "^4.4.1",
- "sort-array": "^4.1.5"
- },
- "dependencies": {
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "debug": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
- "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "glob": {
- "version": "9.3.5",
- "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
- "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "minimatch": "^8.0.2",
- "minipass": "^4.2.4",
- "path-scurry": "^1.6.1"
- }
- },
- "globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "requires": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- }
- },
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "dev": true,
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "minimatch": {
- "version": "8.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
- "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- },
- "minipass": {
- "version": "4.2.8",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
- "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
- "dev": true
- },
- "rimraf": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz",
- "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==",
- "dev": true,
- "requires": {
- "glob": "^9.2.0"
- }
- }
- }
- },
"@bahmutov/cypress-esbuild-preprocessor": {
"version": "2.2.0",
"dev": true,
@@ -14126,6 +14225,8 @@
"@cypress/browserify-preprocessor": {
"version": "3.0.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@babel/core": "^7.16.0",
"@babel/plugin-proposal-class-properties": "^7.16.0",
@@ -15130,6 +15231,8 @@
"acorn-node": {
"version": "1.8.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"acorn": "^7.0.0",
"acorn-walk": "^7.0.0",
@@ -15138,13 +15241,17 @@
"dependencies": {
"acorn": {
"version": "7.4.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
"acorn-walk": {
"version": "7.2.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"agent-base": {
"version": "6.0.2",
@@ -15267,12 +15374,6 @@
"dequal": "^2.0.3"
}
},
- "array-back": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz",
- "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==",
- "dev": true
- },
"array-buffer-byte-length": {
"version": "1.0.0",
"dev": true,
@@ -15295,6 +15396,8 @@
"asn1.js": {
"version": "5.4.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^4.0.0",
"inherits": "^2.0.1",
@@ -15304,13 +15407,17 @@
"dependencies": {
"bn.js": {
"version": "4.12.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
"assert": {
"version": "1.5.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"object-assign": "^4.1.1",
"util": "0.10.3"
@@ -15318,11 +15425,15 @@
"dependencies": {
"inherits": {
"version": "2.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"util": {
"version": "0.10.3",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "2.0.1"
}
@@ -15392,11 +15503,14 @@
},
"babel-plugin-add-module-exports": {
"version": "1.0.4",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"babel-plugin-polyfill-corejs2": {
"version": "0.4.3",
"dev": true,
+ "peer": true,
"requires": {
"@babel/compat-data": "^7.17.7",
"@babel/helper-define-polyfill-provider": "^0.4.0",
@@ -15405,13 +15519,15 @@
"dependencies": {
"semver": {
"version": "6.3.0",
- "dev": true
+ "dev": true,
+ "peer": true
}
}
},
"babel-plugin-polyfill-corejs3": {
"version": "0.8.1",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-define-polyfill-provider": "^0.4.0",
"core-js-compat": "^3.30.1"
@@ -15420,6 +15536,7 @@
"babel-plugin-polyfill-regenerator": {
"version": "0.5.0",
"dev": true,
+ "peer": true,
"requires": {
"@babel/helper-define-polyfill-provider": "^0.4.0"
}
@@ -15427,6 +15544,8 @@
"babelify": {
"version": "10.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {}
},
"balanced-match": {
@@ -15462,7 +15581,9 @@
},
"bn.js": {
"version": "5.2.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"brace-expansion": {
"version": "1.1.11",
@@ -15481,11 +15602,15 @@
},
"brorand": {
"version": "1.1.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"browser-pack": {
"version": "6.1.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"combine-source-map": "~0.8.0",
"defined": "^1.0.0",
@@ -15498,6 +15623,8 @@
"browser-resolve": {
"version": "2.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"resolve": "^1.17.0"
}
@@ -15509,6 +15636,8 @@
"browserify": {
"version": "16.5.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"assert": "^1.4.0",
"browser-pack": "^6.0.1",
@@ -15563,6 +15692,8 @@
"browserify-aes": {
"version": "1.2.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0",
@@ -15575,6 +15706,8 @@
"browserify-cipher": {
"version": "1.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"browserify-aes": "^1.0.4",
"browserify-des": "^1.0.0",
@@ -15584,6 +15717,8 @@
"browserify-des": {
"version": "1.0.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"cipher-base": "^1.0.1",
"des.js": "^1.0.0",
@@ -15594,6 +15729,8 @@
"browserify-rsa": {
"version": "4.1.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^5.0.0",
"randombytes": "^2.0.1"
@@ -15602,6 +15739,8 @@
"browserify-sign": {
"version": "4.2.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^5.1.1",
"browserify-rsa": "^4.0.1",
@@ -15617,6 +15756,8 @@
"readable-stream": {
"version": "3.6.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -15628,6 +15769,8 @@
"browserify-zlib": {
"version": "0.2.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"pako": "~1.0.5"
}
@@ -15645,6 +15788,8 @@
"buffer": {
"version": "5.2.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
@@ -15660,11 +15805,15 @@
},
"buffer-xor": {
"version": "1.0.3",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"builtin-status-codes": {
"version": "3.0.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"c8": {
"version": "7.14.0",
@@ -15696,7 +15845,9 @@
},
"cached-path-relative": {
"version": "1.1.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"cachedir": {
"version": "2.3.0",
@@ -15786,6 +15937,8 @@
"chokidar": {
"version": "3.5.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -15809,6 +15962,8 @@
"cipher-base": {
"version": "1.0.4",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -15867,16 +16022,11 @@
"wrap-ansi": "^7.0.0"
}
},
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
- "dev": true,
- "optional": true
- },
"coffeeify": {
"version": "3.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"convert-source-map": "^1.3.0",
"through2": "^2.0.0"
@@ -15884,7 +16034,9 @@
},
"coffeescript": {
"version": "1.12.7",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"color-convert": {
"version": "2.0.1",
@@ -15904,6 +16056,8 @@
"combine-source-map": {
"version": "0.8.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"convert-source-map": "~1.1.0",
"inline-source-map": "~0.6.0",
@@ -15913,7 +16067,9 @@
"dependencies": {
"convert-source-map": {
"version": "1.1.3",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
@@ -15946,6 +16102,8 @@
"concat-stream": {
"version": "1.6.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
@@ -15969,20 +16127,15 @@
},
"console-browserify": {
"version": "1.2.0",
- "dev": true
- },
- "console.table": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz",
- "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==",
"dev": true,
- "requires": {
- "easy-table": "1.1.0"
- }
+ "optional": true,
+ "peer": true
},
"constants-browserify": {
"version": "1.0.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"convert-source-map": {
"version": "1.9.0",
@@ -15991,17 +16144,22 @@
"core-js-compat": {
"version": "3.31.0",
"dev": true,
+ "peer": true,
"requires": {
"browserslist": "^4.21.5"
}
},
"core-util-is": {
"version": "1.0.3",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"create-ecdh": {
"version": "4.0.4",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^4.1.0",
"elliptic": "^6.5.3"
@@ -16009,13 +16167,17 @@
"dependencies": {
"bn.js": {
"version": "4.12.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
"create-hash": {
"version": "1.2.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
@@ -16027,6 +16189,8 @@
"create-hmac": {
"version": "1.1.7",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
@@ -16048,6 +16212,8 @@
"crypto-browserify": {
"version": "3.12.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"browserify-cipher": "^1.0.0",
"browserify-sign": "^4.0.0",
@@ -16149,7 +16315,9 @@
},
"dash-ast": {
"version": "1.0.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"dashdash": {
"version": "1.14.1",
@@ -16241,16 +16409,6 @@
"strip-bom": "^4.0.0"
}
},
- "defaults": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
- "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
- "dev": true,
- "optional": true,
- "requires": {
- "clone": "^1.0.2"
- }
- },
"define-properties": {
"version": "1.2.0",
"dev": true,
@@ -16261,7 +16419,9 @@
},
"defined": {
"version": "1.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"delayed-stream": {
"version": "1.0.0"
@@ -16269,6 +16429,8 @@
"deps-sort": {
"version": "2.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"JSONStream": "^1.0.3",
"shasum-object": "^1.0.0",
@@ -16283,6 +16445,8 @@
"des.js": {
"version": "1.1.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0"
@@ -16291,6 +16455,8 @@
"detective": {
"version": "5.2.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"acorn-node": "^1.8.2",
"defined": "^1.0.0",
@@ -16308,6 +16474,8 @@
"diffie-hellman": {
"version": "5.0.3",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^4.1.0",
"miller-rabin": "^4.0.0",
@@ -16316,7 +16484,9 @@
"dependencies": {
"bn.js": {
"version": "4.12.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
@@ -16340,7 +16510,9 @@
},
"domain-browser": {
"version": "1.2.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"domexception": {
"version": "4.0.0",
@@ -16356,6 +16528,8 @@
"duplexer2": {
"version": "0.1.4",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"readable-stream": "^2.0.2"
}
@@ -16364,15 +16538,6 @@
"version": "0.2.0",
"dev": true
},
- "easy-table": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz",
- "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==",
- "dev": true,
- "requires": {
- "wcwidth": ">=1.0.1"
- }
- },
"ecc-jsbn": {
"version": "0.1.2",
"dev": true,
@@ -16388,6 +16553,8 @@
"elliptic": {
"version": "6.5.4",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
@@ -16400,7 +16567,9 @@
"dependencies": {
"bn.js": {
"version": "4.12.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
@@ -16689,11 +16858,15 @@
},
"events": {
"version": "2.1.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"evp_bytestokey": {
"version": "1.0.3",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"md5.js": "^1.3.4",
"safe-buffer": "^5.1.1"
@@ -16779,7 +16952,9 @@
},
"fast-safe-stringify": {
"version": "2.1.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"fastq": {
"version": "1.15.0",
@@ -16920,7 +17095,9 @@
},
"get-assigned-identifiers": {
"version": "1.2.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"get-caller-file": {
"version": "2.0.5",
@@ -17078,6 +17255,8 @@
"hash-base": {
"version": "3.1.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
@@ -17087,6 +17266,8 @@
"readable-stream": {
"version": "3.6.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -17098,6 +17279,8 @@
"hash.js": {
"version": "1.1.7",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
@@ -17124,6 +17307,8 @@
"hmac-drbg": {
"version": "1.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
@@ -17143,7 +17328,9 @@
},
"htmlescape": {
"version": "1.1.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"http-proxy-agent": {
"version": "5.0.0",
@@ -17165,7 +17352,9 @@
},
"https-browserify": {
"version": "1.0.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"https-proxy-agent": {
"version": "5.0.1",
@@ -17233,6 +17422,8 @@
"inline-source-map": {
"version": "0.6.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"source-map": "~0.5.3"
}
@@ -17240,6 +17431,8 @@
"insert-module-globals": {
"version": "7.2.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"acorn-node": "^1.5.2",
"combine-source-map": "^0.8.0",
@@ -17307,7 +17500,9 @@
},
"is-buffer": {
"version": "1.1.6",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"is-callable": {
"version": "1.2.7",
@@ -17323,6 +17518,7 @@
"is-core-module": {
"version": "2.12.1",
"dev": true,
+ "peer": true,
"requires": {
"has": "^1.0.3"
}
@@ -17345,6 +17541,8 @@
"is-generator-function": {
"version": "1.0.10",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"has-tostringtag": "^1.0.0"
}
@@ -17465,7 +17663,9 @@
},
"isarray": {
"version": "1.0.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"isexe": {
"version": "2.0.0",
@@ -17795,6 +17995,8 @@
"json-stable-stringify": {
"version": "0.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"jsonify": "~0.0.0"
}
@@ -17825,15 +18027,21 @@
},
"jsonify": {
"version": "0.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"jsonparse": {
"version": "1.3.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"JSONStream": {
"version": "1.3.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"jsonparse": "^1.2.0",
"through": ">=2.2.7 <3"
@@ -17874,6 +18082,8 @@
"labeled-stream-splicer": {
"version": "2.0.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.1",
"stream-splicer": "^2.0.0"
@@ -17935,11 +18145,14 @@
},
"lodash.clonedeep": {
"version": "4.5.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"lodash.debounce": {
"version": "4.0.8",
- "dev": true
+ "dev": true,
+ "peer": true
},
"lodash.flattendeep": {
"version": "4.4.0",
@@ -17947,7 +18160,9 @@
},
"lodash.memoize": {
"version": "3.0.4",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"lodash.merge": {
"version": "4.6.2",
@@ -18068,6 +18283,8 @@
"md5.js": {
"version": "1.3.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
@@ -18093,6 +18310,8 @@
"miller-rabin": {
"version": "4.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^4.0.0",
"brorand": "^1.0.1"
@@ -18100,7 +18319,9 @@
"dependencies": {
"bn.js": {
"version": "4.12.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
@@ -18123,11 +18344,15 @@
},
"minimalistic-assert": {
"version": "1.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"minimalistic-crypto-utils": {
"version": "1.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"minimatch": {
"version": "3.1.2",
@@ -18150,7 +18375,9 @@
},
"mkdirp-classic": {
"version": "0.5.3",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"mlly": {
"version": "1.4.0",
@@ -18276,6 +18503,8 @@
"module-deps": {
"version": "6.2.3",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"browser-resolve": "^2.0.0",
"cached-path-relative": "^1.0.2",
@@ -18546,7 +18775,9 @@
},
"os-browserify": {
"version": "0.3.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"ospath": {
"version": "1.2.2",
@@ -18555,6 +18786,8 @@
"outpipe": {
"version": "1.1.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"shell-quote": "^1.4.2"
}
@@ -18603,7 +18836,9 @@
},
"pako": {
"version": "1.0.11",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"parent-module": {
"version": "1.0.1",
@@ -18615,6 +18850,8 @@
"parents": {
"version": "1.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"path-platform": "~0.11.15"
}
@@ -18622,6 +18859,8 @@
"parse-asn1": {
"version": "5.1.6",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"asn1.js": "^5.2.0",
"browserify-aes": "^1.0.0",
@@ -18639,7 +18878,9 @@
},
"path-browserify": {
"version": "0.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"path-exists": {
"version": "4.0.0",
@@ -18655,11 +18896,14 @@
},
"path-parse": {
"version": "1.0.7",
- "dev": true
+ "dev": true,
+ "peer": true
},
"path-platform": {
"version": "0.11.15",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"path-scurry": {
"version": "1.9.2",
@@ -18697,6 +18941,8 @@
"pbkdf2": {
"version": "3.1.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
@@ -18810,11 +19056,15 @@
},
"process": {
"version": "0.11.10",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"process-nextick-args": {
"version": "2.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"process-on-spawn": {
"version": "1.0.0",
@@ -18848,6 +19098,8 @@
"public-encrypt": {
"version": "4.0.3",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"bn.js": "^4.1.0",
"browserify-rsa": "^4.0.0",
@@ -18859,7 +19111,9 @@
"dependencies": {
"bn.js": {
"version": "4.12.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
@@ -18873,7 +19127,9 @@
},
"punycode": {
"version": "1.4.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"qs": {
"version": "6.10.4",
@@ -18884,7 +19140,9 @@
},
"querystring-es3": {
"version": "0.2.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"querystringify": {
"version": "2.2.0",
@@ -18904,6 +19162,8 @@
"randomfill": {
"version": "1.0.4",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"randombytes": "^2.0.5",
"safe-buffer": "^5.1.0"
@@ -18950,6 +19210,8 @@
"read-only-stream": {
"version": "2.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"readable-stream": "^2.0.2"
}
@@ -18957,6 +19219,8 @@
"readable-stream": {
"version": "2.3.8",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -18969,11 +19233,15 @@
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"string_decoder": {
"version": "1.1.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -19001,11 +19269,13 @@
},
"regenerate": {
"version": "1.4.2",
- "dev": true
+ "dev": true,
+ "peer": true
},
"regenerate-unicode-properties": {
"version": "10.1.0",
"dev": true,
+ "peer": true,
"requires": {
"regenerate": "^1.4.2"
}
@@ -19017,6 +19287,7 @@
"regenerator-transform": {
"version": "0.15.1",
"dev": true,
+ "peer": true,
"requires": {
"@babel/runtime": "^7.8.4"
}
@@ -19044,6 +19315,7 @@
"regexpu-core": {
"version": "5.3.2",
"dev": true,
+ "peer": true,
"requires": {
"@babel/regjsgen": "^0.8.0",
"regenerate": "^1.4.2",
@@ -19056,13 +19328,15 @@
"regjsparser": {
"version": "0.9.1",
"dev": true,
+ "peer": true,
"requires": {
"jsesc": "~0.5.0"
},
"dependencies": {
"jsesc": {
"version": "0.5.0",
- "dev": true
+ "dev": true,
+ "peer": true
}
}
},
@@ -19104,6 +19378,7 @@
"resolve": {
"version": "1.22.2",
"dev": true,
+ "peer": true,
"requires": {
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
@@ -19153,6 +19428,8 @@
"ripemd160": {
"version": "2.0.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
@@ -19284,6 +19561,8 @@
"sha.js": {
"version": "2.4.11",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -19292,6 +19571,8 @@
"shasum": {
"version": "1.0.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"json-stable-stringify": "~0.0.0",
"sha.js": "~2.4.4"
@@ -19300,6 +19581,8 @@
"shasum-object": {
"version": "1.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"fast-safe-stringify": "^2.0.7"
}
@@ -19317,7 +19600,9 @@
},
"shell-quote": {
"version": "1.8.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"side-channel": {
"version": "1.0.4",
@@ -19338,7 +19623,9 @@
},
"simple-concat": {
"version": "1.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"slash": {
"version": "3.0.0",
@@ -19353,19 +19640,11 @@
"is-fullwidth-code-point": "^3.0.0"
}
},
- "sort-array": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.5.tgz",
- "integrity": "sha512-Ya4peoS1fgFN42RN1REk2FgdNOeLIEMKFGJvs7VTP3OklF8+kl2SkpVliZ4tk/PurWsrWRsdNdU+tgyOBkB9sA==",
- "dev": true,
- "requires": {
- "array-back": "^5.0.0",
- "typical": "^6.0.1"
- }
- },
"source-map": {
"version": "0.5.7",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"source-map-js": {
"version": "1.0.2",
@@ -19497,6 +19776,8 @@
"stream-browserify": {
"version": "2.0.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "~2.0.1",
"readable-stream": "^2.0.2"
@@ -19512,6 +19793,8 @@
"stream-combiner2": {
"version": "1.1.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"duplexer2": "~0.1.0",
"readable-stream": "^2.0.2"
@@ -19520,6 +19803,8 @@
"stream-http": {
"version": "3.2.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"builtin-status-codes": "^3.0.0",
"inherits": "^2.0.4",
@@ -19530,6 +19815,8 @@
"readable-stream": {
"version": "3.6.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -19541,6 +19828,8 @@
"stream-splicer": {
"version": "2.0.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.1",
"readable-stream": "^2.0.2"
@@ -19549,6 +19838,8 @@
"string_decoder": {
"version": "1.3.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"safe-buffer": "~5.2.0"
}
@@ -19630,6 +19921,8 @@
"subarg": {
"version": "1.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"minimist": "^1.1.0"
}
@@ -19643,7 +19936,8 @@
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
- "dev": true
+ "dev": true,
+ "peer": true
},
"symbol-tree": {
"version": "3.2.4",
@@ -19652,6 +19946,8 @@
"syntax-error": {
"version": "1.4.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"acorn-node": "^1.2.0"
}
@@ -19741,6 +20037,8 @@
"through2": {
"version": "2.0.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
@@ -19753,6 +20051,8 @@
"timers-browserify": {
"version": "1.4.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"process": "~0.11.0"
}
@@ -19841,13 +20141,9 @@
},
"tty-browserify": {
"version": "0.0.1",
- "dev": true
- },
- "tunnel": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
- "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"tunnel-agent": {
"version": "0.6.0",
@@ -19877,7 +20173,9 @@
},
"typedarray": {
"version": "0.0.6",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"typedarray-to-buffer": {
"version": "3.1.5",
@@ -19890,23 +20188,21 @@
"version": "5.1.3",
"dev": true
},
- "typical": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/typical/-/typical-6.0.1.tgz",
- "integrity": "sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A==",
- "dev": true
- },
"ufo": {
"version": "1.1.2",
"dev": true
},
"umd": {
"version": "3.0.3",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"undeclared-identifiers": {
"version": "1.1.3",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"acorn-node": "^1.3.0",
"dash-ast": "^1.0.0",
@@ -19917,11 +20213,13 @@
},
"unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
- "dev": true
+ "dev": true,
+ "peer": true
},
"unicode-match-property-ecmascript": {
"version": "2.0.0",
"dev": true,
+ "peer": true,
"requires": {
"unicode-canonical-property-names-ecmascript": "^2.0.0",
"unicode-property-aliases-ecmascript": "^2.0.0"
@@ -19929,11 +20227,13 @@
},
"unicode-match-property-value-ecmascript": {
"version": "2.1.0",
- "dev": true
+ "dev": true,
+ "peer": true
},
"unicode-property-aliases-ecmascript": {
"version": "2.1.0",
- "dev": true
+ "dev": true,
+ "peer": true
},
"universalify": {
"version": "2.0.0",
@@ -19974,6 +20274,8 @@
"url": {
"version": "0.11.1",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"punycode": "^1.4.1",
"qs": "^6.11.0"
@@ -19982,6 +20284,8 @@
"qs": {
"version": "6.11.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"side-channel": "^1.0.4"
}
@@ -19999,13 +20303,17 @@
"util": {
"version": "0.10.4",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "2.0.3"
},
"dependencies": {
"inherits": {
"version": "2.0.3",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
}
}
},
@@ -20015,7 +20323,9 @@
},
"util-deprecate": {
"version": "1.0.2",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"uuid": {
"version": "9.0.0",
@@ -20172,7 +20482,9 @@
},
"vm-browserify": {
"version": "1.1.2",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"w3c-xmlserializer": {
"version": "4.0.0",
@@ -20205,6 +20517,8 @@
"watchify": {
"version": "4.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"anymatch": "^3.1.0",
"browserify": "^17.0.0",
@@ -20218,6 +20532,8 @@
"browserify": {
"version": "17.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"assert": "^1.4.0",
"browser-pack": "^6.0.1",
@@ -20272,6 +20588,8 @@
"through2": {
"version": "2.0.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
@@ -20281,15 +20599,21 @@
},
"events": {
"version": "3.3.0",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"path-browserify": {
"version": "1.0.1",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"stream-browserify": {
"version": "3.0.0",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
@@ -20298,6 +20622,8 @@
"readable-stream": {
"version": "3.6.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -20309,6 +20635,8 @@
"through2": {
"version": "4.0.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"readable-stream": "3"
},
@@ -20316,6 +20644,8 @@
"readable-stream": {
"version": "3.6.2",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -20327,6 +20657,8 @@
"util": {
"version": "0.12.5",
"dev": true,
+ "optional": true,
+ "peer": true,
"requires": {
"inherits": "^2.0.3",
"is-arguments": "^1.0.4",
@@ -20346,16 +20678,6 @@
"graceful-fs": "^4.1.2"
}
},
- "wcwidth": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
- "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
- "dev": true,
- "optional": true,
- "requires": {
- "defaults": "^1.0.3"
- }
- },
"webidl-conversions": {
"version": "7.0.0",
"dev": true
@@ -20547,7 +20869,9 @@
},
"xtend": {
"version": "4.0.2",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "peer": true
},
"y18n": {
"version": "5.0.8",
diff --git a/src/App.tsx b/src/App.tsx
index 0df674e2..9670ea29 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,22 +1,30 @@
-import { createBrowserRouter, RouterProvider } from "react-router-dom";
-import CreateTest from "./app/home/pages/CreateTest";
-import ListTests from "./app/home/pages/ListTests";
+import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
+import Login from "../src/app/home/pages/Login";
+import Cadastro from "../src/app/home/pages/Cadastro";
+import Reservar from "../src/app/home/pages/Reservar";
+import Perfil from "../src/app/home/pages/Perfil";
+import Avaliacoes from "../src/app/home/pages/Avaliacoes";
+import Recursos from "./app/home/pages/Recursos";
+import Manutencoes from "./app/home/pages/Manutencoes";
+import 'bootstrap/dist/css/bootstrap.min.css';
-const router = createBrowserRouter([
- {
- path: "*",
- Component: CreateTest,
- },
- {
- path: "/create-test",
- Component: CreateTest,
- },
- {
- path: "/tests",
- Component: ListTests,
- },
-]);
-export default function App() {
- return Loading...
} />;
+function App() {
+
+
+ return (
+
+
+ } /> {/* Tela inicial = Login */}
+ } /> {/* Rota para Cadastro */}
+ } /> {/* Rota para Reservas */}
+ } /> {/* Rota para Modal */}
+ } /> {/* Rota para Avaliações */}
+ } /> {/* Rota para Recursos */}
+ } /> {/* Rota para Manutenções */}
+
+
+ );
}
+
+export default App;
diff --git a/src/app/home/pages/Avaliacoes.tsx b/src/app/home/pages/Avaliacoes.tsx
new file mode 100644
index 00000000..d1e3d8d5
--- /dev/null
+++ b/src/app/home/pages/Avaliacoes.tsx
@@ -0,0 +1,24 @@
+//import { useEffect } from "react";
+//import { useNavigate } from "react-router-dom";
+import SideBar from "../../../shared/components/SideBar/SideBar";
+import styles from "../../../shared/components/SideBar/SideBar.module.css";
+
+const Avaliacoes = () => {
+ // const navigate = useNavigate();
+ return (
+
+ {/* Sidebar fixa à esquerda */}
+
+
+
+
+ {/* Conteúdo da página */}
+
+
Avaliações
+
Este é o restante da sua aplicação
+
+
+ );
+};
+
+export default Avaliacoes;
diff --git a/src/app/home/pages/Cadastro.tsx b/src/app/home/pages/Cadastro.tsx
new file mode 100644
index 00000000..6bb6f27f
--- /dev/null
+++ b/src/app/home/pages/Cadastro.tsx
@@ -0,0 +1,96 @@
+import { useState } from "react";
+import { cadastrar } from "../../../shared/services/autorizacao";
+import { useNavigate } from "react-router-dom";
+import Button from "../../../shared/components/Button";
+import Input from "../../../shared/components/Input";
+import ErrorMessage from "../../../shared/components/ErrorMessage";
+import styles from "../styles/Cadastro.module.css";
+import globalStyles from "../../../shared/components/LoginCadastro.module.css";
+
+const Cadastro = () => {
+ const [nome, setNome] = useState("");
+ const [cpf, setCpf] = useState("");
+ const [email, setEmail] = useState("");
+ const [professor, setProfessor] = useState("N");
+ const [siape, setSiape] = useState("");
+ const [senha, setSenha] = useState("");
+ const [confirmarSenha, setConfirmarSenha] = useState("");
+ const [error, setError] = useState("");
+ const [successMessage, setSuccessMessage] = useState("");
+ const navigate = useNavigate();
+
+ const handleCadastro = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ try {
+ const response = await cadastrar({ nome, cpf, email, professor, siape, senha, confirmarSenha });
+
+ if (!response.success) {
+ setError(response.error || "");
+ return;
+ }
+
+ setSuccessMessage("Cadastro realizado com sucesso!");
+ setNome("");
+ setCpf("");
+ setEmail("");
+ setProfessor("N");
+ setSiape("");
+ setSenha("");
+ setConfirmarSenha("");
+ setError("");
+ } catch (err) {
+ setError("Falha no cadastro. Verifique os dados e tente novamente.");
+ }
+ };
+
+ return (
+
+
+
SAGAA
+
+ Sistema de Agendamento e
+ Gerenciamento Acadêmico Automático
+
+
+ {error &&
}
+
+ {successMessage ? (
+
+
{successMessage}
+
+
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export default Cadastro;
diff --git a/src/app/home/pages/Login.tsx b/src/app/home/pages/Login.tsx
new file mode 100644
index 00000000..bce1109e
--- /dev/null
+++ b/src/app/home/pages/Login.tsx
@@ -0,0 +1,68 @@
+import { useState } from "react";
+import { login } from "../../../shared/services/autorizacao";
+import { useNavigate } from "react-router-dom";
+import Button from "../../../shared/components/Button";
+import Input from "../../../shared/components/Input";
+import ErrorMessage from "../../../shared/components/ErrorMessage";
+import styles from "../styles/Login.module.css";
+import globalStyles from "../../../shared/components/LoginCadastro.module.css";
+import Loader from "../../../shared/components/Loader";
+
+const Login = () => {
+ const [email, setEmail] = useState("");
+ const [senha, setPassword] = useState("");
+ const [error, setError] = useState("");
+ const [loading, setLoading] = useState(false);
+ const navigate = useNavigate();
+
+ const handleLogin = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+
+ try {
+ const response = await login(email, senha);
+
+ if (!response.success) {
+ setError(response.error ?? "");
+ setLoading(false);
+ return;
+ }
+
+ navigate("/reservas");
+ } catch (err) {
+ setError("Falha no login. Verifique suas credenciais.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
SAGAA
+
+ Sistema de Agendamento e
+ Gerenciamento Acadêmico Automático
+
+
+ {error &&
}
+
+
+
+
+ Esqueceu a senha?
+ navigate("/cadastro")} className={styles.link}>Não tem conta ainda?
+
+
+
+ );
+};
+
+export default Login;
diff --git a/src/app/home/pages/Manutencoes.tsx b/src/app/home/pages/Manutencoes.tsx
new file mode 100644
index 00000000..08db54cb
--- /dev/null
+++ b/src/app/home/pages/Manutencoes.tsx
@@ -0,0 +1,293 @@
+import { useState, useEffect } from "react";
+import SideBar from "../../../shared/components/SideBar/SideBar";
+import styles from "../../../shared/components/SideBar/SideBar.module.css";
+
+type Reserva = {
+ id: number;
+ sala_id: string;
+ data: string;
+ start_time: string;
+ end_time: string;
+ status: string;
+};
+
+type SolicitacaoManutencao = {
+ id: number;
+ reserva_id: number;
+ descricao: string;
+};
+
+const PegarReservasFinalizadas = async (professorId: number): Promise => {
+ try {
+ const resposta = await fetch(`http://127.0.0.1:5000/api/reservas/${professorId}`);
+ const reservas: Reserva[] = await resposta.json();
+ return reservas.filter((reserva) => reserva.status === "finalizada" || reserva.status === "ativa");
+ } catch (erro) {
+ console.error("Erro ao buscar reservas finalizadas:", erro);
+ return [];
+ }
+};
+
+const Manutencoes = () => {
+ const [reservasFinalizadas, setReservasFinalizadas] = useState([]);
+ const [solicitacoesManutencao, setSolicitacoesManutencao] = useState<{
+ [key: number]: SolicitacaoManutencao;
+ }>({});
+ const [descricaoPorReserva, setDescricaoPorReserva] = useState<{ [key: number]: string }>({});
+ const [editando, setEditando] = useState(null); // ID da reserva em edição
+ const [reservaParaExcluir, setReservaParaExcluir] = useState(null); // ID da reserva a ser excluída
+
+ // Supondo que o ID do professor logado seja 3 (substitua pelo valor real)
+ const professorId = 3;
+
+ useEffect(() => {
+ const fetchReservas = async () => {
+ const reservas = await PegarReservasFinalizadas(professorId);
+ setReservasFinalizadas(reservas);
+ };
+ fetchReservas();
+ }, [professorId]);
+
+ const handleSolicitarManutencao = async (reservaId: number) => {
+ const descricao = descricaoPorReserva[reservaId] || "";
+ if (!descricao.trim()) {
+ alert("O campo 'O que havia de errado na sala?' não pode estar vazio.");
+ return;
+ }
+
+ try {
+ const resposta = await fetch("http://127.0.0.1:5000/solicitacoes/manutencao", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ reserva_id: reservaId, descricao }),
+ });
+
+ const resultado = await resposta.json();
+ if (resposta.ok) {
+ alert("Solicitação de manutenção criada com sucesso!");
+ setSolicitacoesManutencao((prev) => ({
+ ...prev,
+ [reservaId]: { id: resultado.id, reserva_id: reservaId, descricao },
+ }));
+ setDescricaoPorReserva((prev) => ({ ...prev, [reservaId]: "" })); // Limpa o campo de texto
+ } else {
+ alert(`Erro: ${resultado.erro || "Erro ao criar solicitação"}`);
+ }
+ } catch (erro) {
+ console.error("Erro ao enviar solicitação:", erro);
+ alert("Erro ao enviar solicitação. Verifique a conexão com o servidor.");
+ }
+ };
+
+ const handleEditarManutencao = async (reservaId: number) => {
+ const descricao = descricaoPorReserva[reservaId] || "";
+ if (!descricao.trim()) {
+ alert("O campo 'O que havia de errado na sala?' não pode estar vazio.");
+ return;
+ }
+
+ const solicitacaoId = solicitacoesManutencao[reservaId].id;
+ try {
+ const resposta = await fetch(`http://127.0.0.1:5000/solicitacoes/manutencao/${solicitacaoId}`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ descricao }),
+ });
+
+ const resultado = await resposta.json();
+ if (resposta.ok) {
+ alert("Solicitação de manutenção atualizada com sucesso!");
+ setSolicitacoesManutencao((prev) => ({
+ ...prev,
+ [reservaId]: { ...prev[reservaId], descricao },
+ }));
+ setDescricaoPorReserva((prev) => ({ ...prev, [reservaId]: "" })); // Limpa o campo de texto
+ setEditando(null); // Sai do modo de edição
+ } else {
+ alert(`Erro: ${resultado.erro || "Erro ao editar solicitação"}`);
+ }
+ } catch (erro) {
+ console.error("Erro ao editar solicitação:", erro);
+ alert("Erro ao editar solicitação. Verifique a conexão com o servidor.");
+ }
+ };
+
+ const handleExcluirManutencao = async (reservaId: number) => {
+ const solicitacaoId = solicitacoesManutencao[reservaId].id;
+ try {
+ const resposta = await fetch(`http://127.0.0.1:5000/solicitacoes/manutencao/${solicitacaoId}`, {
+ method: "DELETE",
+ });
+
+ if (resposta.ok) {
+ alert("Solicitação de manutenção excluída com sucesso!");
+ setSolicitacoesManutencao((prev) => {
+ const newSolicitacoes = { ...prev };
+ delete newSolicitacoes[reservaId];
+ return newSolicitacoes;
+ });
+ setDescricaoPorReserva((prev) => ({ ...prev, [reservaId]: "" })); // Limpa o campo de texto
+ setEditando(null); // Sai do modo de edição
+ } else {
+ const resultado = await resposta.json();
+ alert(`Erro: ${resultado.erro || "Erro ao excluir solicitação"}`);
+ }
+ } catch (erro) {
+ console.error("Erro ao excluir solicitação:", erro);
+ alert("Erro ao excluir solicitação. Verifique a conexão com o servidor.");
+ }
+ setReservaParaExcluir(null); // Fecha o popup após a exclusão
+ };
+
+ return (
+
+ {/* Sidebar fixa à esquerda */}
+
+
+
+
+ {/* Conteúdo da página */}
+
+
Solicitação de Manutenções
+ {reservasFinalizadas.length > 0 ? (
+ reservasFinalizadas.map((reserva) => (
+
+
Sala {reserva.sala_id}
+
Data: {reserva.data} | Hora: {reserva.start_time} às {reserva.end_time}
+
+ {solicitacoesManutencao[reserva.id] && editando !== reserva.id ? (
+ <>
+
Solicitação realizada:
+
{solicitacoesManutencao[reserva.id].descricao}
+
+
+
+
+ >
+ ) : (
+ <>
+
+ ))
+ ) : (
+
Nenhuma reserva finalizada encontrada.
+ )}
+
+ {/* Popup de confirmação de exclusão */}
+ {reservaParaExcluir !== null && (
+
+
+
+ Tem certeza que deseja excluir essa solicitação? Essa ação é irreversível.
+
+
+
+
+
+
+
+ )}
+
+
+ );
+};
+
+export default Manutencoes;
\ No newline at end of file
diff --git a/src/app/home/pages/Perfil.tsx b/src/app/home/pages/Perfil.tsx
new file mode 100644
index 00000000..46e3f8f2
--- /dev/null
+++ b/src/app/home/pages/Perfil.tsx
@@ -0,0 +1,25 @@
+import SideBar from "../../../shared/components/SideBar/SideBar";
+import styles from "../../../shared/components/SideBar/SideBar.module.css";
+import { useNavigate } from "react-router-dom";
+
+
+const Perfil = () => {
+ const navigate = useNavigate();
+ return (
+
+ {/* Sidebar fixa à esquerda */}
+
+
+
+
+ {/* Conteúdo da página */}
+
+
Perfil
+
Este é o restante da sua aplicação
+
+
+
+ );
+};
+
+export default Perfil;
diff --git a/src/app/home/pages/Recursos.tsx b/src/app/home/pages/Recursos.tsx
new file mode 100644
index 00000000..809c050f
--- /dev/null
+++ b/src/app/home/pages/Recursos.tsx
@@ -0,0 +1,344 @@
+import { useState, useEffect } from "react";
+import SideBar from "../../../shared/components/SideBar/SideBar";
+import styles from "../../../shared/components/SideBar/SideBar.module.css";
+
+type Reserva = {
+ id: number;
+ sala_id: string;
+ data: string;
+ start_time: string;
+ end_time: string;
+ status: string;
+};
+
+const PegarReservaAtiva = async (): Promise => {
+ try {
+ const resposta = await fetch("http://127.0.0.1:5000/api/reservas");
+ const reservas: Reserva[] = await resposta.json();
+ return reservas.filter((reserva) => reserva.status === "ativa");
+ } catch (erro) {
+ console.error("Erro ao buscar reservas ativas:", erro);
+ return [];
+ }
+};
+
+const SolicitacaoRecursos = () => {
+ const [reservasAtivas, setReservasAtivas] = useState([]);
+ const [reservaSelecionada, setReservaSelecionada] = useState(null);
+ const [selectedItems, setSelectedItems] = useState([]);
+ const [outrosItens, setOutrosItens] = useState("");
+ const [observacoes, setObservacoes] = useState("");
+ const [solicitacoesCriadas, setSolicitacoesCriadas] = useState<{
+ [key: number]: {
+ id: number; // Adicionado o ID da solicitação
+ recursos: string;
+ itens_nao_listados: string;
+ observacoes: string;
+ reserva_id: number;
+ }
+ }>({});
+ const [showConfirmacaoExclusao, setShowConfirmacaoExclusao] = useState(false); // Estado para controlar o popup
+ const [editando, setEditando] = useState(false); // Estado para controlar o modo de edição
+
+ useEffect(() => {
+ const fetchReservas = async () => {
+ const reservas = await PegarReservaAtiva();
+ setReservasAtivas(reservas);
+ if (reservas.length > 0) setReservaSelecionada(reservas[0]);
+ };
+ fetchReservas();
+ }, []);
+
+ const handleReservaChange = (event: React.ChangeEvent) => {
+ const reservaId = parseInt(event.target.value);
+ const reserva = reservasAtivas.find((res) => res.id === reservaId) || null;
+ setReservaSelecionada(reserva);
+ setSelectedItems([]);
+ setOutrosItens("");
+ setObservacoes("");
+ setEditando(false); // Sai do modo de edição ao trocar de reserva
+ };
+
+ const handleSubmit = async () => {
+ if (!reservaSelecionada) {
+ alert("Selecione uma reserva ativa!");
+ return;
+ }
+
+ const dados = {
+ recursos: selectedItems.join(", "),
+ itens_nao_listados: outrosItens,
+ observacoes,
+ reserva_id: reservaSelecionada.id,
+ };
+
+ try {
+ let resposta;
+ if (editando && solicitacoesCriadas[reservaSelecionada.id]) {
+ // Modo de edição: envia uma requisição PUT para atualizar a solicitação
+ const idSolicitacao = solicitacoesCriadas[reservaSelecionada.id].id;
+ resposta = await fetch(`http://127.0.0.1:5000/solicitacoes/recursos/${idSolicitacao}`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(dados),
+ });
+
+ const resultado = await resposta.json();
+ if (resposta.ok) {
+ alert("Solicitação de recursos alterada.");
+ // Atualiza o estado com os novos dados
+ setSolicitacoesCriadas((prev) => ({
+ ...prev,
+ [reservaSelecionada.id]: { ...dados, id: idSolicitacao }, // Mantém o mesmo ID
+ }));
+ setSelectedItems([]);
+ setOutrosItens("");
+ setObservacoes("");
+ setEditando(false);
+ } else {
+ alert(`Erro: ${resultado.erro || "Erro ao editar solicitação"}`);
+ }
+ } else {
+ // Modo de criação: envia uma requisição POST para criar uma nova solicitação
+ resposta = await fetch("http://127.0.0.1:5000/solicitacoes/recursos", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(dados),
+ });
+
+ const resultado = await resposta.json();
+ if (resposta.ok) {
+ alert("Parabéns, sua solicitação de recursos foi criada!");
+ setSolicitacoesCriadas((prev) => ({
+ ...prev,
+ [reservaSelecionada.id]: { ...dados, id: resultado.id }, // Salva o novo ID
+ }));
+ setSelectedItems([]);
+ setOutrosItens("");
+ setObservacoes("");
+ } else {
+ alert(`Erro: ${resultado.erro || "Erro ao criar solicitação"}`);
+ }
+ }
+ } catch (erro) {
+ console.error("Erro ao enviar solicitação:", erro);
+ alert("Erro ao enviar solicitação. Verifique a conexão com o servidor.");
+ }
+ };
+
+ const handleExcluir = async () => {
+ if (reservaSelecionada && solicitacoesCriadas[reservaSelecionada.id]) {
+ const idSolicitacao = solicitacoesCriadas[reservaSelecionada.id].id;
+ try {
+ const resposta = await fetch(`http://127.0.0.1:5000/solicitacoes/recursos/${idSolicitacao}`, {
+ method: "DELETE",
+ });
+
+ if (resposta.ok) {
+ alert("Solicitação excluída com sucesso!");
+ // Remove a solicitação do estado
+ setSolicitacoesCriadas((prev) => {
+ const newSolicitacoes = { ...prev };
+ delete newSolicitacoes[reservaSelecionada.id];
+ return newSolicitacoes;
+ });
+ } else {
+ const resultado = await resposta.json();
+ alert(`Erro: ${resultado.erro || "Erro ao excluir solicitação"}`);
+ }
+ } catch (erro) {
+ console.error("Erro ao excluir solicitação:", erro);
+ alert("Erro ao excluir solicitação. Verifique a conexão com o servidor.");
+ }
+ }
+ setShowConfirmacaoExclusao(false); // Fecha o popup após a exclusão
+ };
+
+ const handleAlterar = () => {
+ if (reservaSelecionada && solicitacoesCriadas[reservaSelecionada.id]) {
+ const solicitacao = solicitacoesCriadas[reservaSelecionada.id];
+ setSelectedItems(solicitacao.recursos.split(", "));
+ setOutrosItens(solicitacao.itens_nao_listados);
+ setObservacoes(solicitacao.observacoes);
+ setEditando(true); // Entra no modo de edição
+ } else {
+ alert("Solicitação não encontrada.");
+ }
+ };
+
+ const solicitacaoCriada = reservaSelecionada ? solicitacoesCriadas[reservaSelecionada.id] : null;
+
+ return (
+
+ {/* Sidebar fixa à esquerda */}
+
+
+
+
+ {/* Conteúdo da página */}
+
+
{/* Ajuste aqui */}
+
Próximas Reservas
+
+ {reservasAtivas.length > 0 ? (
+ <>
+
+
+
+ {reservaSelecionada && (
+ <>
+
Sala: {reservaSelecionada.sala_id}
+
Data: {reservaSelecionada.data}
+
Hora: {reservaSelecionada.start_time} às {reservaSelecionada.end_time}
+ >
+ )}
+
+ {solicitacaoCriada && !editando ? (
+ <>
+
Itens: {solicitacaoCriada.recursos || "Nenhum"}
+
Itens não listados: {solicitacaoCriada.itens_nao_listados || "Nenhum"}
+
Quantidades e observações: {solicitacaoCriada.observacoes || "Nenhuma"}
+
+
+ >
+ ) : (
+ <>
+
+ {[
+ ["Cabo USB", "Cabo P2", "Cabo HDMI", "Cabo VGA"],
+ ["Extensão", "Microfone", "Mesa de som", "Passador"],
+ ["Televisor", "Projetor", "Carregador", "Pen Drive"],
+ ["Mouse", "Teclado", "Monitor", "USB-C HDMI"],
+ ["Cafeteira", "Gelágua", "Apagador", "Piloto"],
+ ].map((coluna, colIndex) => (
+
+ {coluna.map((item) => (
+
+ ))}
+
+ ))}
+
+
+
setOutrosItens(e.target.value)}
+ style={{ width: "100%", marginTop: "10px", padding: "10px", marginBottom: "20px", fontSize: "16px" }}
+ />
+
+
setObservacoes(e.target.value)}
+ style={{ width: "100%", marginTop: "10px", padding: "10px", marginBottom: "20px", fontSize: "16px" }}
+ />
+
+
+ >
+ )}
+ >
+ ) : (
+
Nenhuma reserva ativa encontrada.
+ )}
+
+ {/* Popup de confirmação de exclusão */}
+ {showConfirmacaoExclusao && (
+
+
+
Tem certeza que deseja excluir essa solicitação?
+
+
+
+
+
+
+ )}
+
+
+
+ );
+};
+
+export default SolicitacaoRecursos;
\ No newline at end of file
diff --git a/src/app/home/pages/Reservar.tsx b/src/app/home/pages/Reservar.tsx
new file mode 100644
index 00000000..5d4d622d
--- /dev/null
+++ b/src/app/home/pages/Reservar.tsx
@@ -0,0 +1,40 @@
+//import { useEffect } from "react";
+//import { useNavigate } from "react-router-dom";
+import SideBar from "../../../shared/components/SideBar/SideBar";
+import styles from "../../../shared/components/SideBar/SideBar.module.css";
+import Dropdown from 'react-bootstrap/Dropdown';
+
+
+const Reservar = () => {
+ //const navigate = useNavigate();
+
+ return (
+
+ {/* Sidebar fixa à esquerda */}
+
+
+
+
+ {/* Conteúdo da página */}
+
+
+
+
+ Dropdown Button
+
+
+
+ Action
+ Another action
+ Something else
+
+
+
+
Salas Disponíveis
+
+
+
+ );
+};
+
+export default Reservar;
diff --git a/src/app/home/styles/Cadastro.module.css b/src/app/home/styles/Cadastro.module.css
new file mode 100644
index 00000000..356f84a6
--- /dev/null
+++ b/src/app/home/styles/Cadastro.module.css
@@ -0,0 +1,70 @@
+.title {
+ font-size: 22px;
+ font-weight: bold;
+ color: #333;
+ }
+
+.subtitle {
+font-size: 14px;
+color: #666;
+margin-bottom: 20px;
+}
+
+.form {
+display: flex;
+flex-direction: column;
+gap: 10px;
+}
+
+.button {
+background-color: #6200ea !important; /* Roxo */
+color: #fff;
+font-size: 16px;
+padding: 5px;
+border-radius: 5px;
+border: none;
+cursor: pointer;
+transition: background-color 0.3s;}
+
+.button:hover {
+ background-color: #4b00c2 !important; /* Roxo mais escuro no hover */
+ }
+
+.button:disabled {
+ background-color: #ccc;
+ cursor: not-allowed;
+ }
+
+.select {
+ width: 100%;
+ padding: 10px;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+ font-size: 16px;
+ background-color: #fff;
+ }
+
+.select:focus {
+ border-color: #6200ea; /* Destaca ao focar */
+ outline: none;
+ }
+
+
+.footer {
+ display: flex;
+ justify-content: space-between; /* Distribui os elementos horizontalmente */
+ align-items: center; /* Alinha verticalmente */
+ margin-top: 20px;
+ gap: 10px; /* Espaço entre o link e o botão */
+}
+
+.link {
+ font-size: 14px;
+ color: #666;
+ cursor: pointer;
+ text-decoration: underline; /* Remove o underline */
+}
+
+ .link:hover {
+ color: #333; /* Tom mais escuro ao passar o mouse */
+ }
\ No newline at end of file
diff --git a/src/app/home/styles/Login.module.css b/src/app/home/styles/Login.module.css
new file mode 100644
index 00000000..d7fbbda4
--- /dev/null
+++ b/src/app/home/styles/Login.module.css
@@ -0,0 +1,42 @@
+.title {
+ font-size: 22px;
+ font-weight: bold;
+ color: #333;
+}
+
+.subtitle {
+ font-size: 14px;
+ color: #666;
+ margin-bottom: 20px;
+}
+
+.form {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.button {
+ background-color: #6200ea; /* Roxo forte */
+ color: #fff;
+ font-size: 16px;
+ padding: 10px;
+ border-radius: 5px;
+ border: none;
+ cursor: pointer;
+ transition: background-color 0.3s;
+
+}
+
+.links {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 15px;
+ font-size: 12px;
+ color: #666;
+}
+
+.link {
+ cursor: pointer;
+ text-decoration: underline;
+}
\ No newline at end of file
diff --git a/src/shared/components/Button/Button.tsx b/src/shared/components/Button/Button.tsx
new file mode 100644
index 00000000..a19680a6
--- /dev/null
+++ b/src/shared/components/Button/Button.tsx
@@ -0,0 +1,28 @@
+import React from "react";
+
+interface ButtonProps extends React.ButtonHTMLAttributes {
+ children: React.ReactNode;
+}
+
+const Button: React.FC = ({ children, ...props }) => {
+ return (
+
+ );
+};
+
+export default Button;
\ No newline at end of file
diff --git a/src/shared/components/ErrorMessage.tsx b/src/shared/components/ErrorMessage.tsx
new file mode 100644
index 00000000..2f8a6058
--- /dev/null
+++ b/src/shared/components/ErrorMessage.tsx
@@ -0,0 +1,16 @@
+// src/shared/components/ErrorMessage.tsx
+import React from "react";
+
+interface ErrorMessageProps {
+ message: string;
+}
+
+const ErrorMessage: React.FC = ({ message }) => {
+ return (
+
+ {message}
+
+ );
+};
+
+export default ErrorMessage;
diff --git a/src/shared/components/Input.tsx b/src/shared/components/Input.tsx
new file mode 100644
index 00000000..f1fa6227
--- /dev/null
+++ b/src/shared/components/Input.tsx
@@ -0,0 +1,25 @@
+// src/shared/components/Input.tsx
+import React from "react";
+
+interface InputProps extends React.InputHTMLAttributes {
+ onValueChange: (value: string) => void;
+}
+
+const Input: React.FC = ({ onValueChange, ...props }) => {
+ return (
+ onValueChange(e.target.value)}
+ style={{
+ width: "100%",
+ padding: "10px",
+ marginBottom: "10px",
+ border: "1px solid #ccc",
+ borderRadius: "5px",
+ fontSize: "16px",
+ }}
+ />
+ );
+};
+
+export default Input;
diff --git a/src/shared/components/Loader.tsx b/src/shared/components/Loader.tsx
new file mode 100644
index 00000000..ad6a3589
--- /dev/null
+++ b/src/shared/components/Loader.tsx
@@ -0,0 +1,11 @@
+import React from "react";
+
+const Loader: React.FC = () => {
+ return (
+
+ 🔄
+
+ );
+};
+
+export default Loader;
diff --git a/src/shared/components/LoginCadastro.module.css b/src/shared/components/LoginCadastro.module.css
new file mode 100644
index 00000000..b0e835cf
--- /dev/null
+++ b/src/shared/components/LoginCadastro.module.css
@@ -0,0 +1,19 @@
+/* Estilos compartilhados */
+
+.container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ background-color: #ffffff;
+ }
+
+.card {
+ width: 450px;
+ padding: 30px;
+ background-color: #eaeaea; /* Um cinza mais escuro */
+ border-radius: 10px;
+ box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
+ text-align: center;
+}
+
\ No newline at end of file
diff --git a/src/shared/components/SideBar/SideBar.jsx b/src/shared/components/SideBar/SideBar.jsx
new file mode 100644
index 00000000..2e64fef9
--- /dev/null
+++ b/src/shared/components/SideBar/SideBar.jsx
@@ -0,0 +1,48 @@
+// components/Sidebar.jsx
+import { Link, useLocation } from 'react-router-dom';
+import styles from './Sidebar.module.css';
+
+const Sidebar = () => {
+ const location = useLocation();
+
+ // Configuração dos itens do menu
+ const menuItems = [
+ { type: 'link', path: '/perfil', label: '‣ Perfil' },
+ { type: 'title', label: 'Atividades' },
+ { type: 'link', path: '/reservar', label: '‣ Reservar' },
+ { type: 'link', path: '/avaliacoes', label: '‣ Avaliações' },
+ { type: 'title', label: 'Solicitações' },
+ { type: 'link', path: '/recursos', label: '‣ Recursos' },
+ { type: 'link', path: '/manutencoes', label: '‣ Manutenções' },
+ ];
+
+ return (
+
+ );
+};
+
+export default Sidebar;
\ No newline at end of file
diff --git a/src/shared/components/SideBar/SideBar.module.css b/src/shared/components/SideBar/SideBar.module.css
new file mode 100644
index 00000000..9c914297
--- /dev/null
+++ b/src/shared/components/SideBar/SideBar.module.css
@@ -0,0 +1,87 @@
+/* Reset para garantir consistência */
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+/* Container principal */
+.container {
+ display: flex;
+ min-height: 100vh;
+}
+
+/* Sidebar */
+.sidebarWrapper {
+ width: 250px; /* Alterado para combinar com a margem */
+ position: fixed;
+ height: 100vh;
+ left: 0;
+ top: 0;
+ background: #f0f0f0; /* Cor mais neutra */
+ z-index: 1000;
+ padding: 20px;
+}
+
+/* Conteúdo principal (fora da sidebar)*/
+.contentWrapper {
+ flex: 1;
+ margin-left: 250px; /* Igual à largura da sidebar */
+ padding: 30px;
+ min-height: 100vh;
+ background: #fff; /* Fundo branco padrão */
+}
+
+/* Título SAGAA */
+.title {
+ color: #2c3e50;
+ padding-bottom: 15px;
+ padding-left: 10px;
+ margin-bottom: 15px;
+ border-bottom: 2px solid #e0e0e0; /* Borda sutil */
+ font-size: 2rem;
+}
+
+/* Menu */
+.menu {
+ list-style: none;
+ padding: 0px;
+ margin: 50px 0px;
+}
+
+/* Seções (Atividades, Solicitações) */
+.sectionTitle {
+ color: #8f9b8d;
+ font-size: 1.2rem;
+ letter-spacing: 0px;
+ margin: 50px 0 10px 0;
+ padding-left: 10px;
+}
+
+/* Itens (Perfil, Reservar, Avaliações, Recursos, Manutenções) */
+.menuItem {
+ padding: 0px 15px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ margin: 10px 0;
+ color: #34495e;
+ font-size: 1.1rem;
+}
+
+
+
+/* Links ativos - Adicionar classe .active */
+.active {
+ background-color: #f0f0f0 !important;
+ color: #6200ea !important;
+}
+
+.link {
+ text-decoration: none;
+ color: inherit;
+ font-weight: normal;
+}
+
+.link:hover {
+ color: #6200ea;
+}
\ No newline at end of file
diff --git a/src/shared/services/ApiService.ts b/src/shared/services/ApiService.ts
index 3e94dded..7b73f211 100644
--- a/src/shared/services/ApiService.ts
+++ b/src/shared/services/ApiService.ts
@@ -58,22 +58,18 @@ export class ApiService {
}
}
- public async post(
+ public async post(
path: string,
body: any
- ): Promise> {
+ ): Promise | FailureResult> {
try {
- const response = await this.httpClient.post(path, body, {
+ const response = await this.httpClient.post(path, body, {
headers: this.headers,
});
- const baseApiResponseModel = new BaseApiResponseModel(response.data);
-
- return new SuccessResult(baseApiResponseModel);
+ return new SuccessResult(response.data);
} catch (e) {
- const error = e as Error | AxiosError;
-
- return this.handleHttpError(error);
+ return this.handleHttpError(e as AxiosError);
}
}
@@ -116,3 +112,4 @@ export class ApiService {
}
}
}
+
diff --git a/src/shared/services/autorizacao.tsx b/src/shared/services/autorizacao.tsx
new file mode 100644
index 00000000..67387867
--- /dev/null
+++ b/src/shared/services/autorizacao.tsx
@@ -0,0 +1,48 @@
+import axios from "axios";
+
+const apiInstance = axios.create({
+ baseURL: import.meta.env.VITE_API_URL,
+ headers: { "Content-Type": "application/json" },
+});
+
+export interface ApiResponse {
+ success: boolean;
+ error?: string;
+ message?: string;
+}
+
+
+export const login = async (email: string, senha: string): Promise => {
+ try {
+ const response = await apiInstance.post("/", { email, senha });
+
+ if (response.status === 200 && response.data.success) {
+ return { success: true, message: "Login realizado com sucesso!" };
+ }
+
+ return { success: false, error: response.data.error || "Erro no login" };
+ } catch (error) {
+ const errorMessage =
+ axios.isAxiosError(error)
+ ? error.response?.data?.error || error.message || "Erro desconhecido ao conectar ao servidor."
+ : "Erro desconhecido ao conectar ao servidor.";
+ return { success: false, error: errorMessage };
+ }
+};
+export const cadastrar = async (dadosUsuario: any): Promise => {
+ try {
+ const response = await apiInstance.post("/cadastro", dadosUsuario);
+
+ if (response.status == 201 && response.data.message) {
+ return { success: true, message: "Cadastro realizado com sucesso!" };
+ }
+
+ return { success: false, error: response.data.error || "Erro no cadastro" };
+ } catch (error) {
+ const errorMessage =
+ axios.isAxiosError(error)
+ ? error.response?.data?.error || error.message || "Erro desconhecido ao conectar ao servidor."
+ : "Erro desconhecido ao conectar ao servidor.";
+ return { success: false, error: errorMessage };
+ }
+};
diff --git a/src/tests/Cadastro.test.tsx b/src/tests/Cadastro.test.tsx
new file mode 100644
index 00000000..9d9f8e67
--- /dev/null
+++ b/src/tests/Cadastro.test.tsx
@@ -0,0 +1,57 @@
+import { render, fireEvent } from "@testing-library/react";
+import Cadastro from "../app/home/pages/Cadastro";
+import { describe, it, expect, vi } from "vitest";
+import { cadastrar } from "../shared/services/autorizacao";
+import { MemoryRouter } from "react-router-dom";
+
+vi.mock("../shared/services/autorizacao", () => ({
+ cadastrar: vi.fn(),
+}));
+
+describe("Cadastro Component", () => {
+ it("Realiza o cadastro com sucesso", async () => {
+ vi.mocked(cadastrar).mockResolvedValueOnce({
+ success: true,
+ message: "Cadastro realizado com sucesso!",
+ });
+
+ const { getByPlaceholderText, getByText, findByText } = render(
+
+
+
+ );
+
+ fireEvent.change(getByPlaceholderText("Nome"), { target: { value: "João" } });
+ fireEvent.change(getByPlaceholderText("CPF"), { target: { value: "123.456.789-00" } });
+ fireEvent.change(getByPlaceholderText("Email"), { target: { value: "joao@gmail.com" } });
+ fireEvent.change(getByPlaceholderText("Senha"), { target: { value: "123456" } });
+ fireEvent.change(getByPlaceholderText("Confirmar senha"), { target: { value: "123456" } });
+
+ fireEvent.click(getByText("Criar"));
+
+ expect(await findByText("Cadastro realizado com sucesso!")).toBeInTheDocument();
+ });
+
+ it("Exibe mensagem de erro ao tentar cadastrar um usuário já existente", async () => {
+ vi.mocked(cadastrar).mockResolvedValueOnce({
+ success: false,
+ error: "email/cpf já está registrado.",
+ });
+
+ const { getByPlaceholderText, getByText, findByText } = render(
+
+
+
+ );
+
+ fireEvent.change(getByPlaceholderText("Nome"), { target: { value: "João" } });
+ fireEvent.change(getByPlaceholderText("CPF"), { target: { value: "123.456.789-00" } });
+ fireEvent.change(getByPlaceholderText("Email"), { target: { value: "joao@gmail.com" } });
+ fireEvent.change(getByPlaceholderText("Senha"), { target: { value: "123456" } });
+ fireEvent.change(getByPlaceholderText("Confirmar senha"), { target: { value: "123456" } });
+
+ fireEvent.click(getByText("Criar"));
+
+ expect(await findByText("email/cpf já está registrado.")).toBeInTheDocument();
+ });
+});
\ No newline at end of file
diff --git a/src/tests/Login.test.tsx b/src/tests/Login.test.tsx
new file mode 100644
index 00000000..075c23aa
--- /dev/null
+++ b/src/tests/Login.test.tsx
@@ -0,0 +1,67 @@
+import { render, fireEvent, waitFor } from "@testing-library/react";
+import Login from "../app/home/pages/Login";
+import { MemoryRouter } from "react-router-dom";
+import { describe, it, expect, vi } from "vitest";
+import { login } from "../shared/services/autorizacao";
+import * as router from "react-router-dom";
+
+// Mock da função login
+vi.mock("../shared/services/autorizacao", () => ({
+ login: vi.fn(),
+}));
+
+// Mock do useNavigate com tipagem explícita
+vi.mock("react-router-dom", async () => {
+ const actual = await vi.importActual("react-router-dom");
+ return {
+ ...actual,
+ useNavigate: vi.fn(),
+ };
+});
+
+describe("Login Component", () => {
+ it("Realiza o login com sucesso e redireciona", async () => {
+ const mockNavigate = vi.fn();
+ vi.mocked(router.useNavigate).mockReturnValue(mockNavigate);
+
+ vi.mocked(login).mockResolvedValueOnce({
+ success: true,
+ message: "Login realizado com sucesso!",
+ });
+
+ const { getByPlaceholderText, getByText } = render(
+
+
+
+ );
+
+ fireEvent.change(getByPlaceholderText("Email"), { target: { value: "joao@gmail.com" } });
+ fireEvent.change(getByPlaceholderText("Senha"), { target: { value: "123456" } });
+
+ fireEvent.click(getByText("Entrar"));
+
+ await waitFor(() => {
+ expect(mockNavigate).toHaveBeenCalledWith("/reservas");
+ });
+ });
+
+ it("Exibe mensagem de erro ao falhar no login", async () => {
+ vi.mocked(login).mockResolvedValueOnce({
+ success: false,
+ error: "Usuário ou senha inválidos.",
+ });
+
+ const { getByPlaceholderText, getByText, findByText } = render(
+
+
+
+ );
+
+ fireEvent.change(getByPlaceholderText("Email"), { target: { value: "email_invalido@gmail.com" } });
+ fireEvent.change(getByPlaceholderText("Senha"), { target: { value: "senha_invalida" } });
+
+ fireEvent.click(getByText("Entrar"));
+
+ expect(await findByText("Usuário ou senha inválidos.")).toBeInTheDocument();
+ });
+});
\ No newline at end of file