diff --git a/backend/pom.xml b/backend/pom.xml index b05c8de..6bf708d 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -84,6 +84,11 @@ h2 test + + org.springframework.security + spring-security-test + test + diff --git a/backend/src/main/java/br/com/fiap/vigisus/config/SecurityConfig.java b/backend/src/main/java/br/com/fiap/vigisus/config/SecurityConfig.java index 147644a..967565b 100644 --- a/backend/src/main/java/br/com/fiap/vigisus/config/SecurityConfig.java +++ b/backend/src/main/java/br/com/fiap/vigisus/config/SecurityConfig.java @@ -31,6 +31,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/actuator/**").permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll() .requestMatchers("/api/**").permitAll() + .requestMatchers("/admin/**").permitAll() .anyRequest().authenticated() ); return http.build(); diff --git a/backend/src/main/java/br/com/fiap/vigisus/controller/AdminDashboardController.java b/backend/src/main/java/br/com/fiap/vigisus/controller/AdminDashboardController.java new file mode 100644 index 0000000..758e8fc --- /dev/null +++ b/backend/src/main/java/br/com/fiap/vigisus/controller/AdminDashboardController.java @@ -0,0 +1,52 @@ +package br.com.fiap.vigisus.controller; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.MeterRegistry; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.Instant; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/admin") +@Tag(name = "Admin Dashboard", description = "Resumo operacional e métricas de uso da API") +@CrossOrigin(origins = "*") +@RequiredArgsConstructor +public class AdminDashboardController { + + private final MeterRegistry meterRegistry; + + @GetMapping("/resumo") + @Operation(summary = "Resumo geral de uso da API com contadores de buscas") + public Map getResumo() { + Counter counter = meterRegistry.find("vigisus.buscas.total").counter(); + double buscasTotal = counter != null ? counter.count() : 0.0; + return Map.of( + "buscas_total", buscasTotal, + "timestamp", Instant.now().toString() + ); + } + + @GetMapping("/top-municipios") + @Operation(summary = "Top municípios mais consultados por volume de buscas") + public List> getTopMunicipios() { + return meterRegistry.find("vigisus.buscas.municipio") + .counters() + .stream() + .sorted(Comparator.comparingDouble(Counter::count).reversed()) + .map(c -> Map.of( + "municipio", String.valueOf(c.getId().getTag("municipio")), + "total", c.count() + )) + .collect(Collectors.toList()); + } +} diff --git a/backend/src/test/java/br/com/fiap/vigisus/controller/AdminDashboardControllerTest.java b/backend/src/test/java/br/com/fiap/vigisus/controller/AdminDashboardControllerTest.java new file mode 100644 index 0000000..1738a74 --- /dev/null +++ b/backend/src/test/java/br/com/fiap/vigisus/controller/AdminDashboardControllerTest.java @@ -0,0 +1,45 @@ +package br.com.fiap.vigisus.controller; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.search.Search; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(AdminDashboardController.class) +@WithMockUser +class AdminDashboardControllerTest { + + @Autowired MockMvc mockMvc; + + @MockBean MeterRegistry meterRegistry; + + @Test + void deveRetornarResumoVazioSemMedidas() throws Exception { + when(meterRegistry.find(any())).thenReturn(Search.in(meterRegistry)); + + mockMvc.perform(get("/admin/resumo")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.buscas_total").isNumber()) + .andExpect(jsonPath("$.timestamp").isString()); + } + + @Test + void deveRetornarListaVaziaParaTopMunicipios() throws Exception { + when(meterRegistry.find("vigisus.buscas.municipio")) + .thenReturn(Search.in(meterRegistry)); + + mockMvc.perform(get("/admin/top-municipios")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray()); + } +}