Terminado todos os controladores e correção de bugs e segurança
This commit is contained in:
37
.gitignore
vendored
Normal file
37
.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Maven
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
# Eclipse
|
||||
.settings/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# IntelliJ IDEA
|
||||
.idea/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
*.factorypath
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
64
COMOUSARAAPI.md
Normal file
64
COMOUSARAAPI.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Guia de Uso da API - Agenda Digital para Estudantes
|
||||
|
||||
Esta API foi desenvolvida em **Java (Spring Boot)** com **MongoDB** para auxiliar estudantes na organização de tarefas e compromissos acadêmicos.
|
||||
|
||||
## Autenticação
|
||||
|
||||
A maioria dos endpoints requer autenticação via **Token JWT**. Para obtê-lo:
|
||||
|
||||
1. Realize o login em `POST /api/estudantes/login`.
|
||||
2. Extraia o campo `token` do corpo da resposta.
|
||||
3. Inclua o token no cabeçalho de todas as requisições subsequentes:
|
||||
|
||||
```
|
||||
Authorization: Bearer SEU_TOKEN_AQUI
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Estudantes
|
||||
|
||||
| Método | Rota | Descrição |
|
||||
|--------|------|-----------|
|
||||
| `POST` | `/api/estudantes/cadastro` | Cria um novo estudante |
|
||||
| `POST` | `/api/estudantes/login` | Autentica e retorna o token JWT |
|
||||
|
||||
### Tarefas
|
||||
|
||||
| Método | Rota | Descrição |
|
||||
|--------|------|-----------|
|
||||
| `POST` | `/api/tarefas` | Cria uma nova tarefa |
|
||||
| `GET` | `/api/tarefas/estudante/{id}` | Lista todas as tarefas de um estudante |
|
||||
| `GET` | `/api/tarefas/estudante/{id}/pendentes` | Lista apenas as tarefas não concluídas |
|
||||
| `GET` | `/api/tarefas/{id}` | Retorna os detalhes de uma tarefa específica |
|
||||
| `PUT` | `/api/tarefas/{id}` | Atualiza os dados de uma tarefa existente |
|
||||
| `PATCH` | `/api/tarefas/{id}/concluir` | Marca uma tarefa como concluída |
|
||||
| `DELETE` | `/api/tarefas/{id}` | Remove uma tarefa |
|
||||
|
||||
---
|
||||
|
||||
## Formato de Resposta
|
||||
|
||||
Todas as respostas da API seguem a estrutura abaixo:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": { ... },
|
||||
"message": "Sucesso",
|
||||
"timestamp": "2026-03-01T19:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execução
|
||||
|
||||
```bash
|
||||
# Iniciar a aplicação
|
||||
mvn spring-boot:run
|
||||
|
||||
# Executar os testes
|
||||
mvn test
|
||||
```
|
||||
18
LICENSE
Normal file
18
LICENSE
Normal file
@@ -0,0 +1,18 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 axel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
154
README.md
Normal file
154
README.md
Normal file
@@ -0,0 +1,154 @@
|
||||
<div align="center">
|
||||
|
||||
<h1>FocusAgenda</h1>
|
||||
|
||||
<p><strong>Plataforma digital de organização de estudos para alunos do ensino médio e técnico</strong></p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/badge/Java-ED8B00?style=for-the-badge&logo=openjdk&logoColor=white" />
|
||||
<img src="https://img.shields.io/badge/MongoDB-4EA94B?style=for-the-badge&logo=mongodb&logoColor=white" />
|
||||
<img src="https://img.shields.io/badge/HTML5-E34F26?style=for-the-badge&logo=html5&logoColor=white" />
|
||||
<img src="https://img.shields.io/badge/CSS3-1572B6?style=for-the-badge&logo=css3&logoColor=white" />
|
||||
<img src="https://img.shields.io/badge/JavaScript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/badge/Status-Em%20Desenvolvimento-orange?style=for-the-badge" />
|
||||
<img src="https://img.shields.io/badge/Licença-MIT-blue?style=for-the-badge" />
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## Sobre o Projeto
|
||||
|
||||
O **FocusAgenda** é uma plataforma digital desenvolvida como Trabalho de Conclusão de Curso (TCC) na **ETEC Pedro D'Arcádia Neto**, no curso Técnico em Desenvolvimento de Sistemas.
|
||||
|
||||
A proposta nasce de um problema real: muitos estudantes do ensino médio e técnico passam horas na escola e, ao chegar em casa, ainda precisam lidar com inúmeras atividades — o que torna difícil manter uma rotina de estudos organizada e eficiente.
|
||||
|
||||
O FocusAgenda oferece uma solução simples e prática para isso: um calendário interativo com notificações, lembretes e visualizações diárias, semanais e mensais, ajudando o aluno a gerenciar seu tempo com mais autonomia e produtividade.
|
||||
|
||||
---
|
||||
|
||||
## Funcionalidades
|
||||
|
||||
- **Calendário interativo** com visualizações diária, semanal e mensal
|
||||
- **Criação e edição de eventos** e afazeres em datas específicas
|
||||
- **Notificações e lembretes** de tarefas, provas e compromissos acadêmicos
|
||||
- **Painel informativo (HUD)** com o dia atual, afazeres do dia e feriados do mês
|
||||
- **Sistema de login e cadastro** de usuários
|
||||
- **Design responsivo** — funciona bem em celulares e computadores
|
||||
|
||||
---
|
||||
|
||||
## Tecnologias Utilizadas
|
||||
|
||||
### Frontend
|
||||
| Tecnologia | Uso |
|
||||
|---|---|
|
||||
| **HTML5** | Estrutura das páginas (campos, botões, calendário) |
|
||||
| **CSS3** | Estilização visual, responsividade e identidade do projeto |
|
||||
| **JavaScript** | Interatividade, navegação sem reload e comunicação com o backend |
|
||||
|
||||
### Backend
|
||||
| Tecnologia | Uso |
|
||||
|---|---|
|
||||
| **Java** | Linguagem principal do servidor, processa requisições do frontend |
|
||||
| **MongoDB** | Banco de dados NoSQL, armazena eventos e dados dos alunos |
|
||||
|
||||
---
|
||||
|
||||
## Telas do Sistema
|
||||
|
||||
### Login
|
||||
> Acesso seguro com e-mail e senha. Usuários sem conta podem se cadastrar diretamente pela tela.
|
||||
|
||||
### Cadastro
|
||||
> Criação de perfil com e-mail, nome de usuário e senha.
|
||||
|
||||
### Calendário Mensal
|
||||
> Visão geral do mês com todos os eventos cadastrados. Painel lateral em laranja exibe o dia atual, afazeres do dia e feriados.
|
||||
|
||||
### Calendário Semanal
|
||||
> Visualização dos afazeres da semana atual com navegação entre períodos.
|
||||
|
||||
### Calendário Diário
|
||||
> Detalhamento das atividades do dia selecionado com horários e feriados.
|
||||
|
||||
---
|
||||
|
||||
## Como Executar o Projeto
|
||||
|
||||
### Pré-requisitos
|
||||
|
||||
- [Java 17+](https://www.oracle.com/java/technologies/downloads/)
|
||||
- [Maven](https://maven.apache.org/)
|
||||
- [MongoDB](https://www.mongodb.com/try/download/community) rodando localmente ou via Atlas
|
||||
|
||||
### Passos
|
||||
|
||||
```bash
|
||||
# Clone o repositório
|
||||
git clone https://git.morpheusnox.shop/axel/BackendFocusAgenda.git
|
||||
|
||||
# Entre na pasta do projeto
|
||||
cd projeto
|
||||
|
||||
# Instale as dependências e compile
|
||||
mvn install
|
||||
|
||||
# Execute o servidor
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
> Após iniciar o servidor, acesse o frontend pelo navegador em `http://localhost:8080`
|
||||
|
||||
---
|
||||
|
||||
## Estrutura do Projeto
|
||||
|
||||
```
|
||||
projeto/
|
||||
├── src/
|
||||
│ └── main/
|
||||
│ ├── java/ # Código-fonte do backend (Java)
|
||||
│ └── resources/ # Configurações da aplicação
|
||||
├── pom.xml # Dependências Maven
|
||||
├── .gitignore
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Equipe
|
||||
|
||||
| Nome | Função |
|
||||
|---|---|
|
||||
| Gabriel H. M. Borges | Desenvolvimento |
|
||||
| Fernando M. B. da Cruz | Desenvolvimento |
|
||||
| Gustavo Ferreira Araujo | Desenvolvimento |
|
||||
| Henry E. de Oliveira | Desenvolvimento |
|
||||
| Nádia Sakae Habu | Professora Orientadora |
|
||||
|
||||
---
|
||||
|
||||
## Instituição
|
||||
|
||||
**ETEC Pedro D'Arcádia Neto**
|
||||
Centro Estadual de Educação Tecnológica Paula Souza
|
||||
Curso: Técnico em Desenvolvimento de Sistemas
|
||||
|
||||
---
|
||||
|
||||
## Referencias
|
||||
|
||||
- CETIC. [TIC Educação 2023](https://cetic.br/)
|
||||
- MORAN, José. *Educação e tecnologias: mudar para valer.* 2007.
|
||||
- PROESC. [Engajamento escolar com uma agenda digital.](https://proesc.com/blog/engajamento-escolar-com-uma-agenda-digital-beneficios-e-dicas-praticas/) 2024.
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<sub>Desenvolvido na ETEC Pedro D'Arcádia Neto — 2025/2026</sub>
|
||||
</div>
|
||||
141
pom.xml
Normal file
141
pom.xml
Normal file
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.agendaestudantil</groupId>
|
||||
<artifactId>agenda-digital-estudantes</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>Agenda Digital para Estudantes</name>
|
||||
<description>Backend para agenda digital destinado a estudantes com dificuldade de organização</description>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.12.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.12.6</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.12.3</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.cdimascio</groupId>
|
||||
<artifactId>dotenv-java</artifactId>
|
||||
<version>2.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.agendaestudantil;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AgendaDigitalEstudantesApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AgendaDigitalEstudantesApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.agendaestudantil.configuracao;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.config.EnableMongoAuditing;
|
||||
|
||||
@Configuration
|
||||
@EnableMongoAuditing
|
||||
public class ConfiguracaoMongo {
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.agendaestudantil.configuracao;
|
||||
|
||||
import com.agendaestudantil.filtro.FiltroJwt;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class ConfiguracaoSeguranca {
|
||||
|
||||
private final FiltroJwt filtroJwt;
|
||||
private final String corsAllowedOrigins;
|
||||
|
||||
public ConfiguracaoSeguranca(FiltroJwt filtroJwt, @Value("${cors.allowed.origins}") String corsAllowedOrigins) {
|
||||
this.filtroJwt = filtroJwt;
|
||||
this.corsAllowedOrigins = corsAllowedOrigins;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.csrf(csrf -> csrf.disable())
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/", "/index.html", "/favicon.ico",
|
||||
"/static/**", "/css/**", "/js/**", "/img/**",
|
||||
"/*.css", "/*.js", "/*.ico",
|
||||
"/api/estudantes/cadastro", "/api/estudantes/login",
|
||||
"/swagger-ui/**", "/v3/api-docs/**")
|
||||
.permitAll()
|
||||
.anyRequest().authenticated())
|
||||
.sessionManagement(session -> session
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.addFilterBefore(filtroJwt, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOrigins(List.of(corsAllowedOrigins.split(",")));
|
||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
|
||||
configuration.setAllowedHeaders(List.of("*"));
|
||||
configuration.setExposedHeaders(List.of("Authorization"));
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setMaxAge(3600L);
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
||||
return config.getAuthenticationManager();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.agendaestudantil.configuracao;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class ResourceController {
|
||||
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "forward:/index.html";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.agendaestudantil.controlador;
|
||||
|
||||
import com.agendaestudantil.dto.RequisicaoDisciplinaDTO;
|
||||
import com.agendaestudantil.dto.RespostaApi;
|
||||
import com.agendaestudantil.dto.RespostaDisciplinaDTO;
|
||||
import com.agendaestudantil.entidade.Disciplina;
|
||||
import com.agendaestudantil.servico.DisciplinaServico;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/disciplinas")
|
||||
public class DisciplinaControlador {
|
||||
|
||||
private final DisciplinaServico disciplinaServico;
|
||||
|
||||
public DisciplinaControlador(DisciplinaServico disciplinaServico) {
|
||||
this.disciplinaServico = disciplinaServico;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<RespostaApi<RespostaDisciplinaDTO>> criarDisciplina(
|
||||
@Valid @RequestBody RequisicaoDisciplinaDTO dto) {
|
||||
Disciplina disciplina = new Disciplina();
|
||||
disciplina.setNome(dto.nome());
|
||||
disciplina.setProfessor(dto.professor());
|
||||
disciplina.setSala(dto.sala());
|
||||
disciplina.setCor(dto.cor());
|
||||
|
||||
RespostaDisciplinaDTO resposta = disciplinaServico.criarDisciplina(disciplina, dto.estudanteId());
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(RespostaApi.sucesso(resposta));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}")
|
||||
public ResponseEntity<RespostaApi<List<RespostaDisciplinaDTO>>> listarPorEstudante(
|
||||
@PathVariable String estudanteId) {
|
||||
List<RespostaDisciplinaDTO> disciplinas = disciplinaServico.listarPorEstudante(estudanteId);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(disciplinas));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<RespostaDisciplinaDTO>> buscarPorId(
|
||||
@PathVariable String id,
|
||||
@RequestParam String estudanteId) {
|
||||
RespostaDisciplinaDTO disciplina = disciplinaServico.buscarPorId(id, estudanteId);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(disciplina));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<RespostaDisciplinaDTO>> atualizarDisciplina(
|
||||
@PathVariable String id,
|
||||
@Valid @RequestBody RequisicaoDisciplinaDTO dto) {
|
||||
Disciplina disciplina = new Disciplina();
|
||||
disciplina.setNome(dto.nome());
|
||||
disciplina.setProfessor(dto.professor());
|
||||
disciplina.setSala(dto.sala());
|
||||
disciplina.setCor(dto.cor());
|
||||
|
||||
RespostaDisciplinaDTO resposta = disciplinaServico.atualizarDisciplina(id, disciplina, dto.estudanteId());
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(resposta));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<Void>> excluirDisciplina(
|
||||
@PathVariable String id,
|
||||
@RequestParam String estudanteId) {
|
||||
disciplinaServico.excluirDisciplina(id, estudanteId);
|
||||
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(RespostaApi.sucesso(null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.agendaestudantil.controlador;
|
||||
|
||||
import com.agendaestudantil.dto.RespostaApi;
|
||||
import com.agendaestudantil.dto.RequisicaoCadastroDTO;
|
||||
import com.agendaestudantil.dto.RespostaEstudanteDTO;
|
||||
import com.agendaestudantil.dto.RequisicaoLoginDTO;
|
||||
import com.agendaestudantil.dto.RespostaLoginDTO;
|
||||
import com.agendaestudantil.servico.EstudanteServico;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/estudantes")
|
||||
public class EstudanteControlador {
|
||||
|
||||
private final EstudanteServico estudanteServico;
|
||||
|
||||
public EstudanteControlador(EstudanteServico estudanteServico) {
|
||||
this.estudanteServico = estudanteServico;
|
||||
}
|
||||
|
||||
@PostMapping("/cadastro")
|
||||
public ResponseEntity<RespostaApi<RespostaEstudanteDTO>> cadastrar(@Valid @RequestBody RequisicaoCadastroDTO dto) {
|
||||
RespostaEstudanteDTO resposta = estudanteServico.cadastrar(dto);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(RespostaApi.sucesso(resposta));
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<RespostaApi<RespostaLoginDTO>> login(@Valid @RequestBody RequisicaoLoginDTO dto) {
|
||||
RespostaLoginDTO resposta = estudanteServico.login(dto);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(resposta));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.agendaestudantil.controlador;
|
||||
|
||||
import com.agendaestudantil.dto.RequisicaoEventoDTO;
|
||||
import com.agendaestudantil.dto.RespostaApi;
|
||||
import com.agendaestudantil.dto.RespostaEventoDTO;
|
||||
import com.agendaestudantil.entidade.Evento;
|
||||
import com.agendaestudantil.servico.EventoServico;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/eventos")
|
||||
public class EventoControlador {
|
||||
|
||||
private final EventoServico eventoServico;
|
||||
|
||||
public EventoControlador(EventoServico eventoServico) {
|
||||
this.eventoServico = eventoServico;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<RespostaApi<RespostaEventoDTO>> criarEvento(
|
||||
@Valid @RequestBody RequisicaoEventoDTO dto) {
|
||||
Evento evento = new Evento();
|
||||
evento.setTitulo(dto.titulo());
|
||||
evento.setDescricao(dto.descricao());
|
||||
evento.setTipo(dto.tipo());
|
||||
evento.setLocal(dto.local());
|
||||
evento.setDataHora(dto.dataHora());
|
||||
evento.setDisciplinaId(dto.disciplinaId());
|
||||
|
||||
RespostaEventoDTO resposta = eventoServico.criarEvento(evento, dto.estudanteId());
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(RespostaApi.sucesso(resposta));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}")
|
||||
public ResponseEntity<RespostaApi<List<RespostaEventoDTO>>> listarPorEstudante(
|
||||
@PathVariable String estudanteId) {
|
||||
List<RespostaEventoDTO> eventos = eventoServico.listarPorEstudante(estudanteId);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(eventos));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}/periodo")
|
||||
public ResponseEntity<RespostaApi<List<RespostaEventoDTO>>> listarPorPeriodo(
|
||||
@PathVariable String estudanteId,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime inicio,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime fim) {
|
||||
List<RespostaEventoDTO> eventos = eventoServico.listarPorPeriodo(estudanteId, inicio, fim);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(eventos));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}/proximos")
|
||||
public ResponseEntity<RespostaApi<List<RespostaEventoDTO>>> listarProximosEventos(
|
||||
@PathVariable String estudanteId) {
|
||||
List<RespostaEventoDTO> eventos = eventoServico.listarProximosEventos(estudanteId);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(eventos));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<RespostaEventoDTO>> buscarPorId(
|
||||
@PathVariable String id,
|
||||
@RequestParam String estudanteId) {
|
||||
RespostaEventoDTO evento = eventoServico.buscarPorId(id, estudanteId);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(evento));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<RespostaEventoDTO>> atualizarEvento(
|
||||
@PathVariable String id,
|
||||
@Valid @RequestBody RequisicaoEventoDTO dto) {
|
||||
Evento evento = new Evento();
|
||||
evento.setTitulo(dto.titulo());
|
||||
evento.setDescricao(dto.descricao());
|
||||
evento.setTipo(dto.tipo());
|
||||
evento.setLocal(dto.local());
|
||||
evento.setDataHora(dto.dataHora());
|
||||
evento.setDisciplinaId(dto.disciplinaId());
|
||||
|
||||
RespostaEventoDTO resposta = eventoServico.atualizarEvento(id, evento, dto.estudanteId());
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(resposta));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<Void>> excluirEvento(
|
||||
@PathVariable String id,
|
||||
@RequestParam String estudanteId) {
|
||||
eventoServico.excluirEvento(id, estudanteId);
|
||||
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(RespostaApi.sucesso(null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.agendaestudantil.controlador;
|
||||
|
||||
import com.agendaestudantil.dto.RespostaApi;
|
||||
import com.agendaestudantil.dto.RequisicaoTarefaDTO;
|
||||
import com.agendaestudantil.dto.RespostaTarefaDTO;
|
||||
import com.agendaestudantil.servico.TarefaServico;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/tarefas")
|
||||
public class TarefaControlador {
|
||||
|
||||
private final TarefaServico tarefaServico;
|
||||
|
||||
public TarefaControlador(TarefaServico tarefaServico) {
|
||||
this.tarefaServico = tarefaServico;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<RespostaApi<RespostaTarefaDTO>> criarTarefa(@Valid @RequestBody RequisicaoTarefaDTO dto) {
|
||||
RespostaTarefaDTO tarefa = tarefaServico.criarTarefa(dto);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(RespostaApi.sucesso(tarefa));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}")
|
||||
public ResponseEntity<RespostaApi<List<RespostaTarefaDTO>>> listarTarefasPorEstudante(
|
||||
@PathVariable String estudanteId) {
|
||||
List<RespostaTarefaDTO> tarefas = tarefaServico.listarTarefasPorEstudante(estudanteId);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(tarefas));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}/pendentes")
|
||||
public ResponseEntity<RespostaApi<List<RespostaTarefaDTO>>> listarTarefasPendentes(
|
||||
@PathVariable String estudanteId) {
|
||||
List<RespostaTarefaDTO> tarefas = tarefaServico.listarTarefasPendentes(estudanteId);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(tarefas));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}/data")
|
||||
public ResponseEntity<RespostaApi<List<RespostaTarefaDTO>>> listarTarefasPorData(
|
||||
@PathVariable String estudanteId,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate data) {
|
||||
List<RespostaTarefaDTO> tarefas = tarefaServico.listarTarefasPorData(estudanteId, data);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(tarefas));
|
||||
}
|
||||
|
||||
@GetMapping("/estudante/{estudanteId}/periodo")
|
||||
public ResponseEntity<RespostaApi<List<RespostaTarefaDTO>>> listarTarefasPorPeriodo(
|
||||
@PathVariable String estudanteId,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate inicio,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate fim) {
|
||||
List<RespostaTarefaDTO> tarefas = tarefaServico.listarTarefasPorPeriodo(estudanteId, inicio, fim);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(tarefas));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<RespostaTarefaDTO>> buscarTarefaPorId(@PathVariable String id) {
|
||||
RespostaTarefaDTO dto = tarefaServico.buscarTarefaPorId(id);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(dto));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<RespostaTarefaDTO>> atualizarTarefa(@PathVariable String id,
|
||||
@Valid @RequestBody RequisicaoTarefaDTO dto) {
|
||||
RespostaTarefaDTO tarefa = tarefaServico.atualizarTarefa(id, dto);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(tarefa));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<RespostaApi<Void>> excluirTarefa(@PathVariable String id) {
|
||||
tarefaServico.excluirTarefa(id);
|
||||
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(RespostaApi.sucesso(null));
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}/concluir")
|
||||
public ResponseEntity<RespostaApi<RespostaTarefaDTO>> marcarConcluida(@PathVariable String id) {
|
||||
RespostaTarefaDTO tarefa = tarefaServico.marcarConcluida(id);
|
||||
return ResponseEntity.ok(RespostaApi.sucesso(tarefa));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
public record RequisicaoCadastroDTO(
|
||||
@NotBlank String nome,
|
||||
@Email @NotBlank String email,
|
||||
@NotBlank @Size(min = 6) String senha,
|
||||
@NotBlank String curso,
|
||||
@NotNull @Min(1) Integer periodo
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public record RequisicaoDisciplinaDTO(
|
||||
@NotBlank String nome,
|
||||
String professor,
|
||||
String sala,
|
||||
String cor,
|
||||
@NotBlank String estudanteId
|
||||
) {}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import com.agendaestudantil.entidade.Evento;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public record RequisicaoEventoDTO(
|
||||
@NotBlank String titulo,
|
||||
String descricao,
|
||||
@NotNull Evento.TipoEvento tipo,
|
||||
String local,
|
||||
String disciplinaId,
|
||||
@NotNull LocalDateTime dataHora,
|
||||
@NotBlank String estudanteId
|
||||
) {}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
public record RequisicaoLoginDTO(
|
||||
@Email @NotBlank String email,
|
||||
@NotBlank String senha
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import com.agendaestudantil.entidade.Tarefa;
|
||||
import jakarta.validation.constraints.Future;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public record RequisicaoTarefaDTO(
|
||||
@NotBlank String titulo,
|
||||
String descricao,
|
||||
@NotNull(message = "Prioridade é obrigatória") Tarefa.Prioridade prioridade,
|
||||
Tarefa.StatusTarefa status,
|
||||
@NotNull @Future LocalDate dataEntrega,
|
||||
String disciplinaId,
|
||||
@NotBlank(message = "ID do estudante é obrigatório") String estudanteId
|
||||
) {
|
||||
}
|
||||
9
src/main/java/com/agendaestudantil/dto/RespostaApi.java
Normal file
9
src/main/java/com/agendaestudantil/dto/RespostaApi.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public record RespostaApi<T>(T data, String message, LocalDateTime timestamp) {
|
||||
public static <T> RespostaApi<T> sucesso(T data) {
|
||||
return new RespostaApi<>(data, "Sucesso", LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
public record RespostaDisciplinaDTO(
|
||||
String id,
|
||||
String estudanteId,
|
||||
String nome,
|
||||
String professor,
|
||||
String sala,
|
||||
String cor
|
||||
) {}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
public record RespostaEstudanteDTO(
|
||||
String id,
|
||||
String nome,
|
||||
String email,
|
||||
String curso,
|
||||
Integer periodo
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public record RespostaEventoDTO(
|
||||
String id,
|
||||
String estudanteId,
|
||||
String titulo,
|
||||
String descricao,
|
||||
String tipo,
|
||||
String local,
|
||||
String disciplinaId,
|
||||
LocalDateTime dataHora
|
||||
) {}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
public record RespostaLoginDTO(String token, RespostaEstudanteDTO estudante) {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.agendaestudantil.dto;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public record RespostaTarefaDTO(
|
||||
String id,
|
||||
String titulo,
|
||||
String descricao,
|
||||
String prioridade,
|
||||
String status,
|
||||
LocalDate dataEntrega,
|
||||
String disciplinaId,
|
||||
String estudanteId
|
||||
) {}
|
||||
28
src/main/java/com/agendaestudantil/entidade/Disciplina.java
Normal file
28
src/main/java/com/agendaestudantil/entidade/Disciplina.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.agendaestudantil.entidade;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.CompoundIndex;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Document(collection = "disciplinas")
|
||||
@CompoundIndex(name = "estudante_nome_idx", def = "{estudanteId: 1, nome: 1}")
|
||||
public class Disciplina extends EntidadeAuditoria {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
private String estudanteId;
|
||||
private String nome;
|
||||
private String professor;
|
||||
private String sala;
|
||||
private String cor;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.agendaestudantil.entidade;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public abstract class EntidadeAuditoria {
|
||||
|
||||
@CreatedDate
|
||||
private LocalDateTime dataCriacao;
|
||||
|
||||
@LastModifiedDate
|
||||
private LocalDateTime dataAtualizacao;
|
||||
}
|
||||
33
src/main/java/com/agendaestudantil/entidade/Estudante.java
Normal file
33
src/main/java/com/agendaestudantil/entidade/Estudante.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.agendaestudantil.entidade;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Document(collection = "estudantes")
|
||||
public class Estudante extends EntidadeAuditoria {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Indexed(unique = true)
|
||||
private String email;
|
||||
|
||||
private String nome;
|
||||
|
||||
private String senha;
|
||||
|
||||
private String curso;
|
||||
|
||||
private Integer periodo;
|
||||
}
|
||||
36
src/main/java/com/agendaestudantil/entidade/Evento.java
Normal file
36
src/main/java/com/agendaestudantil/entidade/Evento.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.agendaestudantil.entidade;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.CompoundIndex;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Document(collection = "eventos")
|
||||
@CompoundIndex(name = "estudante_data_hora_idx", def = "{estudanteId: 1, dataHora: 1}")
|
||||
public class Evento extends EntidadeAuditoria {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
private String estudanteId;
|
||||
private String titulo;
|
||||
private String descricao;
|
||||
private TipoEvento tipo;
|
||||
private String local;
|
||||
private String disciplinaId;
|
||||
private LocalDateTime dataHora;
|
||||
|
||||
public enum TipoEvento {
|
||||
AULA, PROVA, TRABALHO, ESTUDO, EXAME, OUTRO
|
||||
}
|
||||
}
|
||||
44
src/main/java/com/agendaestudantil/entidade/Tarefa.java
Normal file
44
src/main/java/com/agendaestudantil/entidade/Tarefa.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package com.agendaestudantil.entidade;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.CompoundIndex;
|
||||
import org.springframework.data.mongodb.core.index.CompoundIndexes;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Document(collection = "tarefas")
|
||||
@CompoundIndexes({
|
||||
@CompoundIndex(name = "estudante_data_entrega_idx", def = "{estudanteId: 1, dataEntrega: 1}"),
|
||||
@CompoundIndex(name = "estudante_status_idx", def = "{estudanteId: 1, status: 1}")
|
||||
})
|
||||
public class Tarefa extends EntidadeAuditoria {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
private String titulo;
|
||||
private String descricao;
|
||||
private Prioridade prioridade;
|
||||
private StatusTarefa status;
|
||||
private LocalDate dataEntrega;
|
||||
private String disciplinaId;
|
||||
private String estudanteId;
|
||||
|
||||
public enum Prioridade {
|
||||
BAIXA, MEDIA, ALTA, URGENTE
|
||||
}
|
||||
|
||||
public enum StatusTarefa {
|
||||
PENDENTE, EM_ANDAMENTO, CONCLUIDA, ATRASADA
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.agendaestudantil.excecao;
|
||||
|
||||
public class ExcecaoNegocio extends RuntimeException {
|
||||
public ExcecaoNegocio(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.agendaestudantil.excecao;
|
||||
|
||||
public class ExcecaoRecursoNaoEncontrado extends RuntimeException {
|
||||
public ExcecaoRecursoNaoEncontrado(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.agendaestudantil.excecao;
|
||||
|
||||
import com.agendaestudantil.dto.RespostaApi;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class ManipuladorExcecaoGlobal {
|
||||
|
||||
@ExceptionHandler(ExcecaoRecursoNaoEncontrado.class)
|
||||
public ResponseEntity<RespostaApi<Void>> handleResourceNotFound(ExcecaoRecursoNaoEncontrado ex) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(new RespostaApi<>(null, ex.getMessage(), LocalDateTime.now()));
|
||||
}
|
||||
|
||||
@ExceptionHandler(ExcecaoNegocio.class)
|
||||
public ResponseEntity<RespostaApi<Void>> handleExcecaoNegocio(ExcecaoNegocio ex) {
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new RespostaApi<>(null, ex.getMessage(), LocalDateTime.now()));
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<RespostaApi<Map<String, String>>> handleValidationException(
|
||||
MethodArgumentNotValidException ex) {
|
||||
Map<String, String> errors = new HashMap<>();
|
||||
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
|
||||
errors.put(error.getField(), error.getDefaultMessage());
|
||||
}
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||
.body(new RespostaApi<>(errors, "Falha na validação", LocalDateTime.now()));
|
||||
}
|
||||
|
||||
@ExceptionHandler(ResponseStatusException.class)
|
||||
public ResponseEntity<RespostaApi<Void>> handleResponseStatusException(ResponseStatusException ex) {
|
||||
return ResponseEntity.status(ex.getStatusCode())
|
||||
.body(new RespostaApi<>(null, ex.getReason(), LocalDateTime.now()));
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<RespostaApi<Void>> handleGenericException(Exception ex) {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(new RespostaApi<>(null, "Erro interno no servidor: " + ex.getMessage(), LocalDateTime.now()));
|
||||
}
|
||||
}
|
||||
62
src/main/java/com/agendaestudantil/filtro/FiltroJwt.java
Normal file
62
src/main/java/com/agendaestudantil/filtro/FiltroJwt.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.agendaestudantil.filtro;
|
||||
|
||||
import com.agendaestudantil.utilitario.UtilJwt;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class FiltroJwt extends OncePerRequestFilter {
|
||||
|
||||
private final UtilJwt utilJwt;
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
public FiltroJwt(UtilJwt utilJwt, UserDetailsService userDetailsService) {
|
||||
this.utilJwt = utilJwt;
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||
String path = request.getRequestURI();
|
||||
return path.equals("/") || path.equals("/index.html") || path.equals("/favicon.ico")
|
||||
|| path.startsWith("/static/") || path.startsWith("/css/") || path.startsWith("/js/")
|
||||
|| path.startsWith("/img/") || path.endsWith(".css") || path.endsWith(".js")
|
||||
|| path.endsWith(".ico") || path.endsWith(".html");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
String header = request.getHeader("Authorization");
|
||||
String token = null;
|
||||
String estudanteId = null;
|
||||
|
||||
if (header != null && header.startsWith("Bearer ")) {
|
||||
token = header.substring(7);
|
||||
estudanteId = utilJwt.getEstudanteIdFromToken(token);
|
||||
}
|
||||
|
||||
if (estudanteId != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(estudanteId);
|
||||
|
||||
if (utilJwt.validateToken(token)) {
|
||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.agendaestudantil.repositorio;
|
||||
|
||||
import com.agendaestudantil.entidade.Disciplina;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface DisciplinaRepositorio extends MongoRepository<Disciplina, String> {
|
||||
List<Disciplina> findByEstudanteId(String estudanteId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.agendaestudantil.repositorio;
|
||||
|
||||
import com.agendaestudantil.entidade.Estudante;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface EstudanteRepositorio extends MongoRepository<Estudante, String> {
|
||||
Optional<Estudante> findByEmail(String email);
|
||||
boolean existsByEmail(String email);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.agendaestudantil.repositorio;
|
||||
|
||||
import com.agendaestudantil.entidade.Evento;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.Query;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface EventoRepositorio extends MongoRepository<Evento, String> {
|
||||
List<Evento> findByEstudanteId(String estudanteId);
|
||||
|
||||
List<Evento> findByDisciplinaId(String disciplinaId);
|
||||
|
||||
@Query("{'estudanteId': ?0, 'dataHora': {$gte: ?1, $lte: ?2}}")
|
||||
List<Evento> findByEstudanteIdAndDataHoraBetween(String estudanteId, LocalDateTime inicio, LocalDateTime fim);
|
||||
|
||||
@Query("{'estudanteId': ?0, 'dataHora': {$gte: ?1}}")
|
||||
List<Evento> findProximosEventosByEstudanteId(String estudanteId, LocalDateTime data);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.agendaestudantil.repositorio;
|
||||
|
||||
import com.agendaestudantil.entidade.Tarefa;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.mongodb.repository.Query;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface TarefaRepositorio extends MongoRepository<Tarefa, String> {
|
||||
List<Tarefa> findByEstudanteId(String estudanteId);
|
||||
|
||||
List<Tarefa> findByEstudanteIdAndStatus(String estudanteId, Tarefa.StatusTarefa status);
|
||||
|
||||
List<Tarefa> findByDisciplinaId(String disciplinaId);
|
||||
|
||||
@Query("{'estudanteId': ?0, 'dataEntrega': ?1}")
|
||||
List<Tarefa> findByEstudanteIdAndDataEntrega(String estudanteId, LocalDate data);
|
||||
|
||||
@Query("{'estudanteId': ?0, 'dataEntrega': {$gte: ?1, $lte: ?2}}")
|
||||
List<Tarefa> findByEstudanteIdAndDataEntregaBetween(String estudanteId, LocalDate inicio, LocalDate fim);
|
||||
|
||||
@Query("{'estudanteId': ?0, 'status': {$ne: ?1}}")
|
||||
List<Tarefa> findTarefasPendentesByEstudanteId(String estudanteId, Tarefa.StatusTarefa status);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.agendaestudantil.seguranca;
|
||||
|
||||
import com.agendaestudantil.entidade.Estudante;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class DetalhesUsuarioPersonalizado implements UserDetails {
|
||||
|
||||
private final Estudante estudante;
|
||||
|
||||
public DetalhesUsuarioPersonalizado(Estudante estudante) {
|
||||
this.estudante = estudante;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return Collections.singleton(new SimpleGrantedAuthority("ROLE_USER"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return estudante.getSenha();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return estudante.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.agendaestudantil.seguranca;
|
||||
|
||||
import com.agendaestudantil.entidade.Estudante;
|
||||
import com.agendaestudantil.repositorio.EstudanteRepositorio;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ServicoAutenticacaoUsuario implements UserDetailsService {
|
||||
|
||||
private final EstudanteRepositorio estudanteRepositorio;
|
||||
|
||||
public ServicoAutenticacaoUsuario(EstudanteRepositorio estudanteRepositorio) {
|
||||
this.estudanteRepositorio = estudanteRepositorio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String estudanteId) throws UsernameNotFoundException {
|
||||
Estudante estudante = estudanteRepositorio.findById(estudanteId)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("Estudante não encontrado"));
|
||||
|
||||
return new DetalhesUsuarioPersonalizado(estudante);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.agendaestudantil.servico;
|
||||
|
||||
import com.agendaestudantil.dto.RespostaDisciplinaDTO;
|
||||
import com.agendaestudantil.entidade.Disciplina;
|
||||
import com.agendaestudantil.excecao.ExcecaoRecursoNaoEncontrado;
|
||||
import com.agendaestudantil.repositorio.DisciplinaRepositorio;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class DisciplinaServico {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DisciplinaServico.class);
|
||||
|
||||
private final DisciplinaRepositorio disciplinaRepositorio;
|
||||
|
||||
public DisciplinaServico(DisciplinaRepositorio disciplinaRepositorio) {
|
||||
this.disciplinaRepositorio = disciplinaRepositorio;
|
||||
}
|
||||
|
||||
private void validarAcesso(String estudanteId) {
|
||||
String authUser = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
if (!authUser.equals(estudanteId)) {
|
||||
log.error("Acesso negado. Usuário {} tentou acessar recurso do estudante {}", authUser, estudanteId);
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Acesso negado");
|
||||
}
|
||||
}
|
||||
|
||||
public RespostaDisciplinaDTO criarDisciplina(Disciplina disciplina, String estudanteId) {
|
||||
log.debug("Criando disciplina para estudante: {}", estudanteId);
|
||||
validarAcesso(estudanteId);
|
||||
|
||||
disciplina.setEstudanteId(estudanteId);
|
||||
Disciplina salva = disciplinaRepositorio.save(disciplina);
|
||||
return toDTO(salva);
|
||||
}
|
||||
|
||||
public List<RespostaDisciplinaDTO> listarPorEstudante(String estudanteId) {
|
||||
log.debug("Listando disciplinas para estudante: {}", estudanteId);
|
||||
validarAcesso(estudanteId);
|
||||
|
||||
return disciplinaRepositorio.findByEstudanteId(estudanteId).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public RespostaDisciplinaDTO buscarPorId(String id, String estudanteId) {
|
||||
Disciplina disciplina = getDisciplinaEntity(id);
|
||||
validarAcesso(disciplina.getEstudanteId());
|
||||
return toDTO(disciplina);
|
||||
}
|
||||
|
||||
public RespostaDisciplinaDTO atualizarDisciplina(String id, Disciplina disciplinaAtualizada, String estudanteId) {
|
||||
Disciplina disciplina = getDisciplinaEntity(id);
|
||||
validarAcesso(disciplina.getEstudanteId());
|
||||
|
||||
disciplina.setNome(disciplinaAtualizada.getNome());
|
||||
disciplina.setProfessor(disciplinaAtualizada.getProfessor());
|
||||
disciplina.setSala(disciplinaAtualizada.getSala());
|
||||
disciplina.setCor(disciplinaAtualizada.getCor());
|
||||
|
||||
return toDTO(disciplinaRepositorio.save(disciplina));
|
||||
}
|
||||
|
||||
public void excluirDisciplina(String id, String estudanteId) {
|
||||
Disciplina disciplina = getDisciplinaEntity(id);
|
||||
validarAcesso(disciplina.getEstudanteId());
|
||||
disciplinaRepositorio.delete(disciplina);
|
||||
}
|
||||
|
||||
private Disciplina getDisciplinaEntity(String id) {
|
||||
return disciplinaRepositorio.findById(id)
|
||||
.orElseThrow(() -> new ExcecaoRecursoNaoEncontrado("Disciplina não encontrada"));
|
||||
}
|
||||
|
||||
private RespostaDisciplinaDTO toDTO(Disciplina disciplina) {
|
||||
return new RespostaDisciplinaDTO(
|
||||
disciplina.getId(),
|
||||
disciplina.getEstudanteId(),
|
||||
disciplina.getNome(),
|
||||
disciplina.getProfessor(),
|
||||
disciplina.getSala(),
|
||||
disciplina.getCor()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.agendaestudantil.servico;
|
||||
|
||||
import com.agendaestudantil.dto.RequisicaoCadastroDTO;
|
||||
import com.agendaestudantil.dto.RespostaEstudanteDTO;
|
||||
import com.agendaestudantil.dto.RequisicaoLoginDTO;
|
||||
import com.agendaestudantil.dto.RespostaLoginDTO;
|
||||
import com.agendaestudantil.entidade.Estudante;
|
||||
import com.agendaestudantil.excecao.ExcecaoNegocio;
|
||||
import com.agendaestudantil.repositorio.EstudanteRepositorio;
|
||||
import com.agendaestudantil.utilitario.UtilJwt;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class EstudanteServico {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EstudanteServico.class);
|
||||
|
||||
private final EstudanteRepositorio estudanteRepositorio;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final UtilJwt utilJwt;
|
||||
|
||||
public EstudanteServico(EstudanteRepositorio estudanteRepositorio, PasswordEncoder passwordEncoder,
|
||||
UtilJwt utilJwt) {
|
||||
this.estudanteRepositorio = estudanteRepositorio;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.utilJwt = utilJwt;
|
||||
}
|
||||
|
||||
public RespostaEstudanteDTO cadastrar(RequisicaoCadastroDTO dto) {
|
||||
log.debug("Acessando método cadastrar para email: {}", dto.email());
|
||||
Optional<Estudante> existente = estudanteRepositorio.findByEmail(dto.email());
|
||||
if (existente.isPresent()) {
|
||||
log.error("Email já cadastrado: {}", dto.email());
|
||||
throw new ExcecaoNegocio("Email já cadastrado");
|
||||
}
|
||||
|
||||
Estudante estudante = new Estudante();
|
||||
estudante.setNome(dto.nome());
|
||||
estudante.setEmail(dto.email());
|
||||
estudante.setSenha(passwordEncoder.encode(dto.senha()));
|
||||
estudante.setCurso(dto.curso());
|
||||
estudante.setPeriodo(dto.periodo());
|
||||
|
||||
Estudante salvo = estudanteRepositorio.save(estudante);
|
||||
return toResponse(salvo);
|
||||
}
|
||||
|
||||
public RespostaLoginDTO login(RequisicaoLoginDTO dto) {
|
||||
log.debug("Acessando método login para email: {}", dto.email());
|
||||
Optional<Estudante> estudanteParam = estudanteRepositorio.findByEmail(dto.email());
|
||||
|
||||
if (estudanteParam.isEmpty()) {
|
||||
log.error("Email ou senha incorretos para email: {}", dto.email());
|
||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Email ou senha incorretos");
|
||||
}
|
||||
|
||||
Estudante estudante = estudanteParam.get();
|
||||
|
||||
if (!passwordEncoder.matches(dto.senha(), estudante.getSenha())) {
|
||||
log.error("Falha ao validar senha para email: {}", dto.email());
|
||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Email ou senha incorretos");
|
||||
}
|
||||
|
||||
String token = utilJwt.generateToken(estudante.getId());
|
||||
return new RespostaLoginDTO(token, toResponse(estudante));
|
||||
}
|
||||
|
||||
private RespostaEstudanteDTO toResponse(Estudante estudante) {
|
||||
return new RespostaEstudanteDTO(
|
||||
estudante.getId(),
|
||||
estudante.getNome(),
|
||||
estudante.getEmail(),
|
||||
estudante.getCurso(),
|
||||
estudante.getPeriodo());
|
||||
}
|
||||
}
|
||||
111
src/main/java/com/agendaestudantil/servico/EventoServico.java
Normal file
111
src/main/java/com/agendaestudantil/servico/EventoServico.java
Normal file
@@ -0,0 +1,111 @@
|
||||
package com.agendaestudantil.servico;
|
||||
|
||||
import com.agendaestudantil.dto.RespostaEventoDTO;
|
||||
import com.agendaestudantil.entidade.Evento;
|
||||
import com.agendaestudantil.excecao.ExcecaoRecursoNaoEncontrado;
|
||||
import com.agendaestudantil.repositorio.EventoRepositorio;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class EventoServico {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EventoServico.class);
|
||||
|
||||
private final EventoRepositorio eventoRepositorio;
|
||||
|
||||
public EventoServico(EventoRepositorio eventoRepositorio) {
|
||||
this.eventoRepositorio = eventoRepositorio;
|
||||
}
|
||||
|
||||
private void validarAcesso(String estudanteId) {
|
||||
String authUser = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
if (!authUser.equals(estudanteId)) {
|
||||
log.error("Acesso negado. Usuário {} tentou acessar recurso do estudante {}", authUser, estudanteId);
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Acesso negado");
|
||||
}
|
||||
}
|
||||
|
||||
public RespostaEventoDTO criarEvento(Evento evento, String estudanteId) {
|
||||
log.debug("Criando evento para estudante: {}", estudanteId);
|
||||
validarAcesso(estudanteId);
|
||||
|
||||
evento.setEstudanteId(estudanteId);
|
||||
Evento salvo = eventoRepositorio.save(evento);
|
||||
return toDTO(salvo);
|
||||
}
|
||||
|
||||
public List<RespostaEventoDTO> listarPorEstudante(String estudanteId) {
|
||||
log.debug("Listando eventos para estudante: {}", estudanteId);
|
||||
validarAcesso(estudanteId);
|
||||
|
||||
return eventoRepositorio.findByEstudanteId(estudanteId).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<RespostaEventoDTO> listarPorPeriodo(String estudanteId, LocalDateTime inicio, LocalDateTime fim) {
|
||||
validarAcesso(estudanteId);
|
||||
return eventoRepositorio.findByEstudanteIdAndDataHoraBetween(estudanteId, inicio, fim).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<RespostaEventoDTO> listarProximosEventos(String estudanteId) {
|
||||
validarAcesso(estudanteId);
|
||||
return eventoRepositorio.findProximosEventosByEstudanteId(estudanteId, LocalDateTime.now()).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public RespostaEventoDTO buscarPorId(String id, String estudanteId) {
|
||||
Evento evento = getEventoEntity(id);
|
||||
validarAcesso(evento.getEstudanteId());
|
||||
return toDTO(evento);
|
||||
}
|
||||
|
||||
public RespostaEventoDTO atualizarEvento(String id, Evento eventoAtualizado, String estudanteId) {
|
||||
Evento evento = getEventoEntity(id);
|
||||
validarAcesso(evento.getEstudanteId());
|
||||
|
||||
evento.setTitulo(eventoAtualizado.getTitulo());
|
||||
evento.setDescricao(eventoAtualizado.getDescricao());
|
||||
evento.setTipo(eventoAtualizado.getTipo());
|
||||
evento.setLocal(eventoAtualizado.getLocal());
|
||||
evento.setDataHora(eventoAtualizado.getDataHora());
|
||||
evento.setDisciplinaId(eventoAtualizado.getDisciplinaId());
|
||||
|
||||
return toDTO(eventoRepositorio.save(evento));
|
||||
}
|
||||
|
||||
public void excluirEvento(String id, String estudanteId) {
|
||||
Evento evento = getEventoEntity(id);
|
||||
validarAcesso(evento.getEstudanteId());
|
||||
eventoRepositorio.delete(evento);
|
||||
}
|
||||
|
||||
private Evento getEventoEntity(String id) {
|
||||
return eventoRepositorio.findById(id)
|
||||
.orElseThrow(() -> new ExcecaoRecursoNaoEncontrado("Evento não encontrado"));
|
||||
}
|
||||
|
||||
private RespostaEventoDTO toDTO(Evento evento) {
|
||||
return new RespostaEventoDTO(
|
||||
evento.getId(),
|
||||
evento.getEstudanteId(),
|
||||
evento.getTitulo(),
|
||||
evento.getDescricao(),
|
||||
evento.getTipo() != null ? evento.getTipo().name() : null,
|
||||
evento.getLocal(),
|
||||
evento.getDisciplinaId(),
|
||||
evento.getDataHora()
|
||||
);
|
||||
}
|
||||
}
|
||||
139
src/main/java/com/agendaestudantil/servico/TarefaServico.java
Normal file
139
src/main/java/com/agendaestudantil/servico/TarefaServico.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package com.agendaestudantil.servico;
|
||||
|
||||
import com.agendaestudantil.dto.RequisicaoTarefaDTO;
|
||||
import com.agendaestudantil.dto.RespostaTarefaDTO;
|
||||
import com.agendaestudantil.entidade.Tarefa;
|
||||
import com.agendaestudantil.excecao.ExcecaoRecursoNaoEncontrado;
|
||||
import com.agendaestudantil.repositorio.TarefaRepositorio;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class TarefaServico {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TarefaServico.class);
|
||||
|
||||
private final TarefaRepositorio tarefaRepositorio;
|
||||
|
||||
public TarefaServico(TarefaRepositorio tarefaRepositorio) {
|
||||
this.tarefaRepositorio = tarefaRepositorio;
|
||||
}
|
||||
|
||||
private void validarAcesso(String estudanteId) {
|
||||
String authUser = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
if (!authUser.equals(estudanteId)) {
|
||||
log.error("Acesso negado. Usuário {} tentou acessar recurso do estudante {}", authUser, estudanteId);
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Acesso negado");
|
||||
}
|
||||
}
|
||||
|
||||
private void validarAcessoTarefa(Tarefa tarefa) {
|
||||
validarAcesso(tarefa.getEstudanteId());
|
||||
}
|
||||
|
||||
public RespostaTarefaDTO criarTarefa(RequisicaoTarefaDTO dto) {
|
||||
log.debug("Criando tarefa para estudante: {}", dto.estudanteId());
|
||||
validarAcesso(dto.estudanteId());
|
||||
|
||||
Tarefa tarefa = new Tarefa();
|
||||
tarefa.setTitulo(dto.titulo());
|
||||
tarefa.setDescricao(dto.descricao());
|
||||
tarefa.setPrioridade(dto.prioridade() != null ? dto.prioridade() : Tarefa.Prioridade.MEDIA);
|
||||
tarefa.setStatus(dto.status() != null ? dto.status() : Tarefa.StatusTarefa.PENDENTE);
|
||||
tarefa.setDataEntrega(dto.dataEntrega());
|
||||
tarefa.setEstudanteId(dto.estudanteId());
|
||||
|
||||
if (dto.disciplinaId() != null) {
|
||||
tarefa.setDisciplinaId(dto.disciplinaId());
|
||||
}
|
||||
|
||||
return toDTO(tarefaRepositorio.save(tarefa));
|
||||
}
|
||||
|
||||
public List<RespostaTarefaDTO> listarTarefasPorEstudante(String estudanteId) {
|
||||
log.debug("Listando tarefas para estudante: {}", estudanteId);
|
||||
validarAcesso(estudanteId);
|
||||
return tarefaRepositorio.findByEstudanteId(estudanteId).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<RespostaTarefaDTO> listarTarefasPendentes(String estudanteId) {
|
||||
log.debug("Listando tarefas pendentes para estudante: {}", estudanteId);
|
||||
validarAcesso(estudanteId);
|
||||
return tarefaRepositorio.findTarefasPendentesByEstudanteId(estudanteId, Tarefa.StatusTarefa.CONCLUIDA).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<RespostaTarefaDTO> listarTarefasPorData(String estudanteId, LocalDate data) {
|
||||
validarAcesso(estudanteId);
|
||||
return tarefaRepositorio.findByEstudanteIdAndDataEntrega(estudanteId, data).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<RespostaTarefaDTO> listarTarefasPorPeriodo(String estudanteId, LocalDate inicio, LocalDate fim) {
|
||||
validarAcesso(estudanteId);
|
||||
return tarefaRepositorio.findByEstudanteIdAndDataEntregaBetween(estudanteId, inicio, fim).stream()
|
||||
.map(this::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public RespostaTarefaDTO buscarTarefaPorId(String id) {
|
||||
return toDTO(getTarefaEntity(id));
|
||||
}
|
||||
|
||||
public RespostaTarefaDTO atualizarTarefa(String id, RequisicaoTarefaDTO dto) {
|
||||
Tarefa tarefa = getTarefaEntity(id);
|
||||
validarAcesso(tarefa.getEstudanteId());
|
||||
|
||||
tarefa.setTitulo(dto.titulo());
|
||||
tarefa.setDescricao(dto.descricao());
|
||||
tarefa.setPrioridade(dto.prioridade() != null ? dto.prioridade() : tarefa.getPrioridade());
|
||||
tarefa.setStatus(dto.status() != null ? dto.status() : tarefa.getStatus());
|
||||
tarefa.setDataEntrega(dto.dataEntrega());
|
||||
|
||||
if (dto.disciplinaId() != null) {
|
||||
tarefa.setDisciplinaId(dto.disciplinaId());
|
||||
}
|
||||
|
||||
return toDTO(tarefaRepositorio.save(tarefa));
|
||||
}
|
||||
|
||||
public void excluirTarefa(String id) {
|
||||
tarefaRepositorio.delete(getTarefaEntity(id));
|
||||
}
|
||||
|
||||
public RespostaTarefaDTO marcarConcluida(String id) {
|
||||
Tarefa tarefa = getTarefaEntity(id);
|
||||
tarefa.setStatus(Tarefa.StatusTarefa.CONCLUIDA);
|
||||
return toDTO(tarefaRepositorio.save(tarefa));
|
||||
}
|
||||
|
||||
private Tarefa getTarefaEntity(String id) {
|
||||
Tarefa tarefa = tarefaRepositorio.findById(id)
|
||||
.orElseThrow(() -> new ExcecaoRecursoNaoEncontrado("Tarefa não encontrada"));
|
||||
validarAcessoTarefa(tarefa);
|
||||
return tarefa;
|
||||
}
|
||||
|
||||
private RespostaTarefaDTO toDTO(Tarefa tarefa) {
|
||||
return new RespostaTarefaDTO(
|
||||
tarefa.getId(),
|
||||
tarefa.getTitulo(),
|
||||
tarefa.getDescricao(),
|
||||
tarefa.getPrioridade() != null ? tarefa.getPrioridade().name() : null,
|
||||
tarefa.getStatus() != null ? tarefa.getStatus().name() : null,
|
||||
tarefa.getDataEntrega(),
|
||||
tarefa.getDisciplinaId(),
|
||||
tarefa.getEstudanteId());
|
||||
}
|
||||
}
|
||||
56
src/main/java/com/agendaestudantil/utilitario/UtilJwt.java
Normal file
56
src/main/java/com/agendaestudantil/utilitario/UtilJwt.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package com.agendaestudantil.utilitario;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
public class UtilJwt {
|
||||
|
||||
private final String secret;
|
||||
|
||||
public UtilJwt(@Value("${jwt.secret}") String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
private SecretKey getSigningKey() {
|
||||
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public String generateToken(String estudanteId) {
|
||||
Date now = new Date();
|
||||
Date expiryDate = new Date(now.getTime() + 24 * 60 * 60 * 1000L);
|
||||
|
||||
return Jwts.builder()
|
||||
.subject(estudanteId)
|
||||
.issuedAt(now)
|
||||
.expiration(expiryDate)
|
||||
.signWith(getSigningKey())
|
||||
.compact();
|
||||
}
|
||||
|
||||
public String getEstudanteIdFromToken(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(getSigningKey())
|
||||
.build()
|
||||
.parseSignedClaims(token)
|
||||
.getPayload();
|
||||
|
||||
return claims.getSubject();
|
||||
}
|
||||
|
||||
public boolean validateToken(String token) {
|
||||
try {
|
||||
Jwts.parser().verifyWith(getSigningKey()).build().parseSignedClaims(token);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/main/resources/application-dev.properties
Normal file
4
src/main/resources/application-dev.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
spring.data.mongodb.uri=${MONGO_URI:mongodb://localhost:27017/agenda_estudantil}
|
||||
cors.allowed.origins=${CORS_ORIGINS:http://localhost:3000}
|
||||
jwt.secret=${JWT_SECRET:8a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7A8B9C0D1E2F3}
|
||||
logging.level.org.springframework.data.mongodb=DEBUG
|
||||
5
src/main/resources/application-prod.properties
Normal file
5
src/main/resources/application-prod.properties
Normal file
@@ -0,0 +1,5 @@
|
||||
spring.data.mongodb.uri=${MONGO_URI}
|
||||
cors.allowed.origins=${CORS_ORIGINS}
|
||||
jwt.secret=${JWT_SECRET}
|
||||
logging.level.root=WARN
|
||||
logging.level.com.agendaestudantil=INFO
|
||||
15
src/main/resources/application.properties
Normal file
15
src/main/resources/application.properties
Normal file
@@ -0,0 +1,15 @@
|
||||
spring.application.name=${APP_NAME:Agenda Digital para Estudantes}
|
||||
server.port=${SERVER_PORT:8080}
|
||||
server.servlet.context-path=/
|
||||
spring.web.resources.static-locations=classpath:/static/
|
||||
spring.mvc.static-path-pattern=/**
|
||||
spring.mvc.contentnegotiation.favor-parameter=true
|
||||
spring.web.resources.add-mappings=true
|
||||
spring.servlet.multipart.enabled=false
|
||||
spring.servlet.multipart.file-size-threshold=2KB
|
||||
spring.http.multipart.enabled=false
|
||||
|
||||
spring.web.resources.cache.cachecontrol.max-age=3600
|
||||
spring.web.resources.cache.cachecontrol.cache-public=true
|
||||
|
||||
spring.profiles.active=${SPRING_PROFILES_ACTIVE:dev}
|
||||
44
src/main/resources/static/index.html
Normal file
44
src/main/resources/static/index.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="pt-br">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>TCC de cria</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!--Barrinha que fica no topo-->
|
||||
<div id="topo">
|
||||
<h1 id="textotop">Focus Agenda</h1>
|
||||
</div>
|
||||
<!--cabo bar-->
|
||||
|
||||
<!--Login e outras coisas-->
|
||||
<div id="log">
|
||||
<h1 class="mens">Bem Vindo!</h1>
|
||||
|
||||
<h3 class="mens">Faça seu login</h3>
|
||||
|
||||
<form method="POST" action="login.html">
|
||||
<div class="campo">
|
||||
<label for="emailid">Email</label>
|
||||
<input type="email" placeholder="Digite seu email" name="email" id="emailid" required>
|
||||
</div>
|
||||
|
||||
<div class="campo">
|
||||
<label for="senhaid">Senha</label>
|
||||
<input type="password" placeholder="Digite sua senha" name="senha" id="senhaid" required>
|
||||
</div>
|
||||
<button type="submit" id="logbtn">Logar</button>
|
||||
</form>
|
||||
<p class="mens"><a href="cadastro.html" id="linkcada">Cadastrar-se</a></p>
|
||||
</div>
|
||||
<!--cabo log-->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
124
src/main/resources/static/style.css
Normal file
124
src/main/resources/static/style.css
Normal file
@@ -0,0 +1,124 @@
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p,
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
color: black;
|
||||
margin: 0;
|
||||
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif
|
||||
}
|
||||
|
||||
label{
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
#log {
|
||||
width: 100% !important;
|
||||
max-width: 320px;
|
||||
}
|
||||
}
|
||||
#topo {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: #111;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: linear-gradient(to right, #C0392B 47%, #7A4951 73%, #114455 87%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
#textotop {
|
||||
padding-left: 20px;
|
||||
font-size: 38px;
|
||||
margin: 0;
|
||||
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
||||
}
|
||||
|
||||
#log {
|
||||
width: 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
color: white;
|
||||
margin-top: 70px; /* Compensa a barra fixa do topo */
|
||||
}
|
||||
#campo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
align-self: center;
|
||||
}
|
||||
#menslog{
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#emailid, #senhaid {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#logbtn {
|
||||
align-self: center;
|
||||
width: 50%;
|
||||
padding: 12px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
background-color: #C0392B;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
#logbtn:hover {
|
||||
background-color: #A03224;
|
||||
}
|
||||
.mens {
|
||||
align-self: center;
|
||||
}
|
||||
#linkcada{
|
||||
color: #111;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.agendaestudantil.servico;
|
||||
|
||||
import com.agendaestudantil.dto.RequisicaoCadastroDTO;
|
||||
import com.agendaestudantil.dto.RespostaEstudanteDTO;
|
||||
import com.agendaestudantil.dto.RequisicaoLoginDTO;
|
||||
import com.agendaestudantil.dto.RespostaLoginDTO;
|
||||
import com.agendaestudantil.entidade.Estudante;
|
||||
import com.agendaestudantil.excecao.ExcecaoNegocio;
|
||||
import com.agendaestudantil.repositorio.EstudanteRepositorio;
|
||||
import com.agendaestudantil.utilitario.UtilJwt;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class EstudanteServicoTest {
|
||||
|
||||
@Mock
|
||||
private EstudanteRepositorio estudanteRepositorio;
|
||||
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private UtilJwt utilJwt;
|
||||
|
||||
@InjectMocks
|
||||
private EstudanteServico estudanteServico;
|
||||
|
||||
private RequisicaoCadastroDTO requisicaoCadastro;
|
||||
private RequisicaoLoginDTO requisicaoLogin;
|
||||
private Estudante estudante;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
requisicaoCadastro = new RequisicaoCadastroDTO("Teste", "teste@teste.com", "123456", "Curso", 1);
|
||||
requisicaoLogin = new RequisicaoLoginDTO("teste@teste.com", "123456");
|
||||
|
||||
estudante = new Estudante();
|
||||
estudante.setId("1");
|
||||
estudante.setNome("Teste");
|
||||
estudante.setEmail("teste@teste.com");
|
||||
estudante.setSenha("encodedPassword");
|
||||
estudante.setCurso("Curso");
|
||||
estudante.setPeriodo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveCadastrarEstudanteComSucesso() {
|
||||
when(estudanteRepositorio.findByEmail(anyString())).thenReturn(Optional.empty());
|
||||
when(passwordEncoder.encode(anyString())).thenReturn("encodedPassword");
|
||||
when(estudanteRepositorio.save(any(Estudante.class))).thenReturn(estudante);
|
||||
|
||||
RespostaEstudanteDTO resposta = estudanteServico.cadastrar(requisicaoCadastro);
|
||||
|
||||
assertNotNull(resposta);
|
||||
assertEquals("Teste", resposta.nome());
|
||||
verify(estudanteRepositorio, times(1)).save(any(Estudante.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveLancarExcecaoAoCadastrarEmailExistente() {
|
||||
when(estudanteRepositorio.findByEmail(anyString())).thenReturn(Optional.of(estudante));
|
||||
|
||||
assertThrows(ExcecaoNegocio.class, () -> estudanteServico.cadastrar(requisicaoCadastro));
|
||||
verify(estudanteRepositorio, never()).save(any(Estudante.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveRealizarLoginComSucesso() {
|
||||
when(estudanteRepositorio.findByEmail(anyString())).thenReturn(Optional.of(estudante));
|
||||
when(passwordEncoder.matches(anyString(), anyString())).thenReturn(true);
|
||||
when(utilJwt.generateToken(anyString())).thenReturn("token123");
|
||||
|
||||
RespostaLoginDTO resposta = estudanteServico.login(requisicaoLogin);
|
||||
|
||||
assertNotNull(resposta);
|
||||
assertEquals("token123", resposta.token());
|
||||
assertEquals("Teste", resposta.estudante().nome());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveRejeitarSenhaInvalida() {
|
||||
when(estudanteRepositorio.findByEmail(anyString())).thenReturn(Optional.of(estudante));
|
||||
when(passwordEncoder.matches(anyString(), anyString())).thenReturn(false);
|
||||
|
||||
assertThrows(ResponseStatusException.class, () -> estudanteServico.login(requisicaoLogin));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveRejeitarEmailNaoEncontrado() {
|
||||
when(estudanteRepositorio.findByEmail(anyString())).thenReturn(Optional.empty());
|
||||
|
||||
assertThrows(ResponseStatusException.class, () -> estudanteServico.login(requisicaoLogin));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.agendaestudantil.servico;
|
||||
|
||||
import com.agendaestudantil.dto.RequisicaoTarefaDTO;
|
||||
import com.agendaestudantil.dto.RespostaTarefaDTO;
|
||||
import com.agendaestudantil.entidade.Tarefa;
|
||||
import com.agendaestudantil.excecao.ExcecaoRecursoNaoEncontrado;
|
||||
import com.agendaestudantil.repositorio.TarefaRepositorio;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class TarefaServicoTest {
|
||||
|
||||
@Mock
|
||||
private TarefaRepositorio tarefaRepositorio;
|
||||
|
||||
@Mock
|
||||
private SecurityContext securityContext;
|
||||
|
||||
@Mock
|
||||
private Authentication authentication;
|
||||
|
||||
@InjectMocks
|
||||
private TarefaServico tarefaServico;
|
||||
|
||||
private RequisicaoTarefaDTO requisicaoTarefa;
|
||||
private Tarefa tarefa;
|
||||
private final String estudanteId = "estudante123";
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
requisicaoTarefa = new RequisicaoTarefaDTO(
|
||||
"Estudar Spring",
|
||||
"Aprender Spring Boot 3",
|
||||
Tarefa.Prioridade.ALTA,
|
||||
Tarefa.StatusTarefa.PENDENTE,
|
||||
LocalDate.now(),
|
||||
null,
|
||||
estudanteId);
|
||||
|
||||
tarefa = new Tarefa();
|
||||
tarefa.setId("tarefa1");
|
||||
tarefa.setTitulo("Estudar Spring");
|
||||
tarefa.setDescricao("Aprender Spring Boot 3");
|
||||
tarefa.setPrioridade(Tarefa.Prioridade.ALTA);
|
||||
tarefa.setStatus(Tarefa.StatusTarefa.PENDENTE);
|
||||
tarefa.setDataEntrega(LocalDate.now());
|
||||
tarefa.setEstudanteId(estudanteId);
|
||||
}
|
||||
|
||||
private void mockAuthentication(String user) {
|
||||
when(securityContext.getAuthentication()).thenReturn(authentication);
|
||||
when(authentication.getName()).thenReturn(user);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveCriarTarefaComSucesso() {
|
||||
mockAuthentication(estudanteId);
|
||||
when(tarefaRepositorio.save(any(Tarefa.class))).thenReturn(tarefa);
|
||||
|
||||
RespostaTarefaDTO resposta = tarefaServico.criarTarefa(requisicaoTarefa);
|
||||
|
||||
assertNotNull(resposta);
|
||||
assertEquals("Estudar Spring", resposta.titulo());
|
||||
verify(tarefaRepositorio, times(1)).save(any(Tarefa.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveLancarExcecaoAoCriarTarefaParaOutroUsuario() {
|
||||
mockAuthentication("outroEstudante");
|
||||
|
||||
assertThrows(ResponseStatusException.class, () -> tarefaServico.criarTarefa(requisicaoTarefa));
|
||||
verify(tarefaRepositorio, never()).save(any(Tarefa.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveListarTarefasPorEstudanteComSucesso() {
|
||||
mockAuthentication(estudanteId);
|
||||
when(tarefaRepositorio.findByEstudanteId(estudanteId)).thenReturn(List.of(tarefa));
|
||||
|
||||
List<RespostaTarefaDTO> tarefas = tarefaServico.listarTarefasPorEstudante(estudanteId);
|
||||
|
||||
assertFalse(tarefas.isEmpty());
|
||||
assertEquals(1, tarefas.size());
|
||||
assertEquals("Estudar Spring", tarefas.get(0).titulo());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveMudarStatusTarefaParaConcluidoComSucesso() {
|
||||
mockAuthentication(estudanteId);
|
||||
when(tarefaRepositorio.findById(anyString())).thenReturn(Optional.of(tarefa));
|
||||
when(tarefaRepositorio.save(any(Tarefa.class))).thenReturn(tarefa);
|
||||
|
||||
RespostaTarefaDTO resposta = tarefaServico.marcarConcluida("tarefa1");
|
||||
|
||||
assertNotNull(resposta);
|
||||
verify(tarefaRepositorio, times(1)).save(any(Tarefa.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deveLancarExcecaoQuandoTarefaNaoEncontrada() {
|
||||
when(tarefaRepositorio.findById(anyString())).thenReturn(Optional.empty());
|
||||
|
||||
assertThrows(ExcecaoRecursoNaoEncontrado.class, () -> tarefaServico.buscarTarefaPorId("tarefaNaoExistente"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user