diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/v2/VisitController.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/v2/VisitController.java new file mode 100644 index 0000000000..31c373f25c --- /dev/null +++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/v2/VisitController.java @@ -0,0 +1,39 @@ +package com.petclinic.bffapigateway.presentationlayer.v2; + +import com.petclinic.bffapigateway.domainclientlayer.VisitsServiceClient; +import com.petclinic.bffapigateway.dtos.Auth.Role; +import com.petclinic.bffapigateway.dtos.Visits.VisitResponseDTO; +import com.petclinic.bffapigateway.utils.Security.Annotations.SecuredEndpoint; +import com.petclinic.bffapigateway.utils.Security.Variables.Roles; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +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 reactor.core.publisher.Flux; + +@RestController +@RequiredArgsConstructor +@RequestMapping("api/v2/gateway/visits") +@Validated +@Slf4j +@CrossOrigin(origins = "http://localhost:3000, http://localhost:80") +public class VisitController { + + private final VisitsServiceClient visitsServiceClient; + + @SecuredEndpoint(allowedRoles = {Roles.ADMIN}) + @GetMapping(value = "", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> getAllVisits() { + return ResponseEntity.ok().body(visitsServiceClient.getAllVisits()); + } + + + //add more endpoints here + + +} diff --git a/api-gateway/src/test/java/com/petclinic/bffapigateway/presentationlayer/v2/visit/VisitControllerUnitTest.java b/api-gateway/src/test/java/com/petclinic/bffapigateway/presentationlayer/v2/visit/VisitControllerUnitTest.java new file mode 100644 index 0000000000..ff14a86188 --- /dev/null +++ b/api-gateway/src/test/java/com/petclinic/bffapigateway/presentationlayer/v2/visit/VisitControllerUnitTest.java @@ -0,0 +1,91 @@ +package com.petclinic.bffapigateway.presentationlayer.v2.visit; + +import com.petclinic.bffapigateway.domainclientlayer.VisitsServiceClient; +import com.petclinic.bffapigateway.dtos.Visits.Status; +import com.petclinic.bffapigateway.dtos.Visits.VisitResponseDTO; +import com.petclinic.bffapigateway.presentationlayer.v2.VisitController; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.Flux; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; + +import static org.mockito.Mockito.*; + +@WebFluxTest(controllers = VisitController.class) +@AutoConfigureWebTestClient +@ContextConfiguration(classes = { + VisitController.class, + VisitsServiceClient.class +}) +public class VisitControllerUnitTest { + @Autowired + private WebTestClient webTestClient; + + @MockBean + private VisitsServiceClient visitsServiceClient; + + private final String BASE_VISIT_URL = "/api/v2/gateway/visits"; + + //VisitResponseDTO Objects for testing purposes + private final VisitResponseDTO visitResponseDTO1 = VisitResponseDTO.builder() + .visitId("V001") + .visitDate(LocalDate.of(2021, 5, 1).atStartOfDay()) + .description("Routine check-up") + .petId("P001") + .petName("Buddy") + .petBirthDate(Date.from(LocalDate.of(2020, 5, 1).atStartOfDay(ZoneId.systemDefault()).toInstant())) + .practitionerId("PR001") + .vetFirstName("John") + .vetLastName("Doe") + .vetEmail("john.doe@example.com") + .vetPhoneNumber("555-1234") + .status(Status.COMPLETED) + .build(); + @Test + void getAllVisits_whenAllPropertiesExist_thenReturnFluxResponseDTO() { + // Arrange + when(visitsServiceClient.getAllVisits()) + .thenReturn(Flux.just(visitResponseDTO1)); + + // Act + webTestClient.get() + .uri(BASE_VISIT_URL) + .accept(MediaType.TEXT_EVENT_STREAM) + .exchange() + .expectStatus().isOk() + .expectBodyList( VisitResponseDTO.class) + .hasSize(1); + // Assert + verify(visitsServiceClient, times(1)).getAllVisits(); + } + + @Test + void getAllVisits_whenNoVisitsExist_thenReturnEmptyFlux(){ + // Arrange + when(visitsServiceClient.getAllVisits()) + .thenReturn(Flux.empty()); // no visits should not throw an error + // Act + webTestClient.get() + .uri(BASE_VISIT_URL) + .accept(MediaType.TEXT_EVENT_STREAM) + .exchange() + .expectStatus().isOk() + .expectBodyList(VisitResponseDTO.class) + .hasSize(0); + // Assert + verify(visitsServiceClient, times(1)).getAllVisits(); + } + +} diff --git a/petclinic-frontend/src/pages/Visit/Visit.tsx b/petclinic-frontend/src/pages/Visit/Visit.tsx new file mode 100644 index 0000000000..00459954a8 --- /dev/null +++ b/petclinic-frontend/src/pages/Visit/Visit.tsx @@ -0,0 +1,10 @@ +import { NavBar } from '@/layouts/AppNavBar'; + +export default function Visits(): JSX.Element { + return ( +
+ +

This is the Visits Page

+
+ ); +}