diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionController.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionController.java index 551ea8b9..341fa82b 100644 --- a/src/main/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionController.java +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionController.java @@ -53,6 +53,7 @@ import uk.nhs.hee.tis.revalidation.connection.service.DisconnectedElasticSearchService; import uk.nhs.hee.tis.revalidation.connection.service.DiscrepanciesElasticSearchService; import uk.nhs.hee.tis.revalidation.connection.service.ElasticsearchQueryHelper; +import uk.nhs.hee.tis.revalidation.connection.service.ExceptionService; @Slf4j @RestController diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/controller/ExceptionLogController.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/controller/ExceptionLogController.java new file mode 100644 index 00000000..be45a658 --- /dev/null +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/controller/ExceptionLogController.java @@ -0,0 +1,38 @@ +package uk.nhs.hee.tis.revalidation.connection.controller; + +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionLogDto; +import uk.nhs.hee.tis.revalidation.connection.service.ExceptionService; + +@Slf4j +@RestController +@RequestMapping("/api/exceptionLog") +public class ExceptionLogController { + private ExceptionService exceptionService; + + public ExceptionLogController(ExceptionService exceptionService) { + this.exceptionService = exceptionService; + } + + private static final String ADMIN = "admin"; + + /** + * GET /exceptions/today : get list of exceptions from today for an admin. + * + * @return the list of ExceptionLogDto + */ + @GetMapping("/today") + public ResponseEntity> getListOfConnectionExceptionsFromToday( + @RequestParam(name = ADMIN) final String admin) { + + log.info("Received request to fetch exceptions for admin: {}", admin); + final var exceptions = exceptionService.getConnectionExceptionLogsFromToday(admin); + return ResponseEntity.ok().body(exceptions); + } +} diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionRecordDto.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionLogDto.java similarity index 83% rename from src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionRecordDto.java rename to src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionLogDto.java index e0644354..e60dbc00 100644 --- a/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionRecordDto.java +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionLogDto.java @@ -21,13 +21,21 @@ package uk.nhs.hee.tis.revalidation.connection.dto; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; + @Data @Builder -public class ExceptionRecordDto { +@AllArgsConstructor +@NoArgsConstructor +public class ExceptionLogDto { private String gmcId; - private String exceptionMessage; + private String errorMessage; + private LocalDateTime timestamp; + private String admin; } diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionResponseDto.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionResponseDto.java index 3728fdce..105114f8 100644 --- a/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionResponseDto.java +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/dto/ExceptionResponseDto.java @@ -32,5 +32,5 @@ public class ExceptionResponseDto { private long countTotal; private long totalPages; private long totalResults; - private List exceptionRecord; + private List exceptionRecord; } diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/entity/ExceptionLog.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/entity/ExceptionLog.java index 128f4506..ff8751f9 100644 --- a/src/main/java/uk/nhs/hee/tis/revalidation/connection/entity/ExceptionLog.java +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/entity/ExceptionLog.java @@ -35,8 +35,8 @@ @Builder @Document(collection = "exceptionLogs") public class ExceptionLog { - @Id + private String id; private String gmcId; private String errorMessage; private LocalDateTime timestamp; diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/mapper/ExceptionLogMapper.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/mapper/ExceptionLogMapper.java new file mode 100644 index 00000000..b53c0e83 --- /dev/null +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/mapper/ExceptionLogMapper.java @@ -0,0 +1,14 @@ +package uk.nhs.hee.tis.revalidation.connection.mapper; + +import java.util.List; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionLogDto; +import uk.nhs.hee.tis.revalidation.connection.entity.ExceptionLog; + +@Mapper(componentModel = "spring") +public interface ExceptionLogMapper { + + @Mapping(target = "id", ignore = true) + List exceptionLogsToExceptionLogDtos(List exceptionLog); +} diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/repository/ExceptionRepository.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/repository/ExceptionRepository.java index 83abb80b..1b1b245a 100644 --- a/src/main/java/uk/nhs/hee/tis/revalidation/connection/repository/ExceptionRepository.java +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/repository/ExceptionRepository.java @@ -21,6 +21,8 @@ package uk.nhs.hee.tis.revalidation.connection.repository; +import java.time.LocalDateTime; +import java.util.List; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; import uk.nhs.hee.tis.revalidation.connection.entity.ExceptionLog; @@ -28,4 +30,6 @@ @Repository public interface ExceptionRepository extends MongoRepository { + List findByAdminAndTimestampBetween(final String admin, final LocalDateTime start, + final LocalDateTime end); } diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ConnectionService.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ConnectionService.java index be8155e5..17534447 100644 --- a/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ConnectionService.java +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ConnectionService.java @@ -31,8 +31,6 @@ import static uk.nhs.hee.tis.revalidation.connection.entity.GmcResponseCode.fromCode; import java.time.LocalDate; -import java.time.ZoneId; -import java.util.Date; import java.util.List; import java.util.Optional; import java.util.UUID; diff --git a/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionService.java b/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionService.java index 042d7426..ba9a24f9 100644 --- a/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionService.java +++ b/src/main/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionService.java @@ -22,23 +22,17 @@ package uk.nhs.hee.tis.revalidation.connection.service; import static java.time.LocalDateTime.now; -import static java.util.stream.Collectors.toList; -import static org.springframework.data.domain.PageRequest.of; -import static org.springframework.data.domain.Sort.Direction.ASC; -import static org.springframework.data.domain.Sort.Direction.DESC; -import static org.springframework.data.domain.Sort.by; -import java.util.HashMap; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; -import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionRecordDto; -import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionRequestDto; -import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionResponseDto; +import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionLogDto; import uk.nhs.hee.tis.revalidation.connection.entity.ExceptionLog; +import uk.nhs.hee.tis.revalidation.connection.mapper.ExceptionLogMapper; import uk.nhs.hee.tis.revalidation.connection.repository.ExceptionRepository; @Slf4j @@ -49,14 +43,19 @@ public class ExceptionService { @Autowired private ExceptionRepository repository; + @Autowired + private ExceptionLogMapper exceptionLogMapper; + /** * Create exception log. * * @param gmcId gmcId of trainees where there are some issue when updating connection - * @param exceptionMessage response code that response from gmc + * @param errorMessage response code that response from gmc + * @param admin the admin that generated the exception log */ - public void createExceptionLog(final String gmcId, final String exceptionMessage, String admin) { - final var exceptionLog = ExceptionLog.builder().gmcId(gmcId).errorMessage(exceptionMessage) + public void createExceptionLog(final String gmcId, final String errorMessage, String admin) { + + final var exceptionLog = ExceptionLog.builder().gmcId(gmcId).errorMessage(errorMessage) .timestamp(now()).admin(admin).build(); repository.save(exceptionLog); @@ -72,42 +71,16 @@ public void removeExceptionLog(final String gmcId) { } /** - * Get exception log. + * Get today's exception logs for a specific admin. * - * @param requestDto request for getting exception log + * @param admin the admin that generated the exception log */ - public ExceptionResponseDto getExceptionLog(final ExceptionRequestDto requestDto) { - final var direction = "asc".equalsIgnoreCase(requestDto.getSortOrder()) ? ASC : DESC; - final var pageableAndSortable = of(requestDto.getPageNumber(), 20, - by(direction, requestDto.getSortColumn())); - - final var exceptionLogPage = repository.findAll(pageableAndSortable); - final var exceptionLogs = exceptionLogPage.get().collect(toList()); - return ExceptionResponseDto.builder() - .totalPages(exceptionLogPage.getTotalPages()) - .totalResults(exceptionLogPage.getTotalElements()) - .exceptionRecord(buildExceptionRecords(exceptionLogs)) - .build(); - } + public List getConnectionExceptionLogsFromToday(String admin) { + LocalDateTime today = LocalDate.now().atStartOfDay(); + LocalDateTime tomorrow = today.plusDays(1); - /** - * Get exception log hashmap. - */ - public Map getExceptionsMap() { - Map exceptionsMap = new HashMap<>(); - List exceptionLogList = repository.findAll(); - for (ExceptionLog exceptionLog: exceptionLogList) { - exceptionsMap.put(exceptionLog.getGmcId(), exceptionLog.getErrorMessage()); - } - return exceptionsMap; + final var todaysExceptions = repository.findByAdminAndTimestampBetween(admin, today, tomorrow); + return exceptionLogMapper.exceptionLogsToExceptionLogDtos(todaysExceptions); } - private List buildExceptionRecords(final List exceptionLogs) { - return exceptionLogs.stream().map(exception -> { - return ExceptionRecordDto.builder() - .gmcId(exception.getGmcId()) - .exceptionMessage(exception.getErrorMessage()) - .build(); - }).collect(toList()); - } } diff --git a/src/test/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionControllerTest.java b/src/test/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionControllerTest.java index b6e411aa..11e2591b 100644 --- a/src/test/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionControllerTest.java +++ b/src/test/java/uk/nhs/hee/tis/revalidation/connection/controller/ConnectionControllerTest.java @@ -61,6 +61,7 @@ import uk.nhs.hee.tis.revalidation.connection.service.DisconnectedElasticSearchService; import uk.nhs.hee.tis.revalidation.connection.service.DiscrepanciesElasticSearchService; + @WebMvcTest(ConnectionController.class) class ConnectionControllerTest { @@ -86,6 +87,7 @@ class ConnectionControllerTest { private ConnectedElasticSearchService connectedElasticSearchService; @MockBean private DisconnectedElasticSearchService disconnectedElasticSearchService; + private String changeReason; private String designatedBodyCode; private String gmcId; @@ -117,6 +119,7 @@ class ConnectionControllerTest { private String exceptionReason1; private String exceptionReason2; + @BeforeEach public void setup() { changeReason = faker.lorem().sentence(); diff --git a/src/test/java/uk/nhs/hee/tis/revalidation/connection/controller/ExceptionLogControllerTest.java b/src/test/java/uk/nhs/hee/tis/revalidation/connection/controller/ExceptionLogControllerTest.java new file mode 100644 index 00000000..794c12f5 --- /dev/null +++ b/src/test/java/uk/nhs/hee/tis/revalidation/connection/controller/ExceptionLogControllerTest.java @@ -0,0 +1,81 @@ +package uk.nhs.hee.tis.revalidation.connection.controller; + +import static java.util.List.of; +import static org.hamcrest.Matchers.hasItem; +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; + +import com.github.javafaker.Faker; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +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.test.web.servlet.MockMvc; +import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionLogDto; +import uk.nhs.hee.tis.revalidation.connection.service.ExceptionService; + +@WebMvcTest(ExceptionLogController.class) +class ExceptionLogControllerTest { + + private final Faker faker = new Faker(); + private String admin; + private LocalDateTime today; + private String gmcId1; + private String gmcId2; + private String exceptionReason1; + private String exceptionReason2; + @Autowired + private MockMvc mockMvc; + @MockBean + private ExceptionService exceptionService; + @InjectMocks + private ExceptionLogController exceptionLogController; + + @BeforeEach + public void setup() { + + admin = faker.internet().emailAddress(); + today = LocalDateTime.now(); + gmcId1 = faker.number().digits(8); + gmcId2 = faker.number().digits(8); + exceptionReason1 = faker.lorem().characters(20); + exceptionReason2 = faker.lorem().characters(20); + } + + @Test + void shouldReturnAllExceptionsFromTodayForAnAdmin() throws Exception { + final var exceptionRecordDtoList = buildExceptionRecordDtoList(); + + when(exceptionService.getConnectionExceptionLogsFromToday(admin)).thenReturn( + exceptionRecordDtoList); + + mockMvc.perform(get("/api/exceptionLog/today") + .param("admin", admin)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.[*].gmcId").value(hasItem(gmcId1))) + .andExpect(jsonPath("$.[*].errorMessage").value(hasItem(exceptionReason1))) + .andExpect(jsonPath("$.[*].admin").value(hasItem(admin))) + .andExpect(jsonPath("$.[*].gmcId").value(hasItem(gmcId2))) + .andExpect(jsonPath("$.[*].errorMessage").value(hasItem(exceptionReason2))) + .andExpect(jsonPath("$.[*].admin").value(hasItem(admin))); + + } + + private List buildExceptionRecordDtoList() { + final var record1 = ExceptionLogDto.builder() + .gmcId(gmcId1).errorMessage(exceptionReason1) + .timestamp(today).admin(admin) + .build(); + final var record2 = ExceptionLogDto.builder() + .gmcId(gmcId2).errorMessage(exceptionReason2) + .timestamp(today).admin(admin) + .build(); + return of(record1, record2); + } +} diff --git a/src/test/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionServiceTest.java b/src/test/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionServiceTest.java index 3b7191e8..03a1553e 100644 --- a/src/test/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionServiceTest.java +++ b/src/test/java/uk/nhs/hee/tis/revalidation/connection/service/ExceptionServiceTest.java @@ -21,30 +21,30 @@ package uk.nhs.hee.tis.revalidation.connection.service; +import static java.util.List.of; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.lessThan; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.springframework.data.domain.Sort.Direction.ASC; -import static org.springframework.data.domain.Sort.by; import com.github.javafaker.Faker; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import java.util.stream.Stream; 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.Spy; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import uk.nhs.hee.tis.revalidation.connection.dto.ExceptionRequestDto; import uk.nhs.hee.tis.revalidation.connection.entity.ExceptionLog; +import uk.nhs.hee.tis.revalidation.connection.mapper.ExceptionLogMapper; +import uk.nhs.hee.tis.revalidation.connection.mapper.ExceptionLogMapperImpl; import uk.nhs.hee.tis.revalidation.connection.repository.ExceptionRepository; @ExtendWith(MockitoExtension.class) @@ -58,24 +58,29 @@ class ExceptionServiceTest { @Mock private ExceptionRepository repository; - @Mock - private Page page; - - @Mock - private ExceptionLog exceptionLog; + @Spy + private ExceptionLogMapper mapper = new ExceptionLogMapperImpl(); private String gmcId; + private String gmcId2; private String responseCode; private LocalDateTime localDateTime; private List exceptionLogList; private String admin; + private String exceptionReason1; + private String exceptionReason2; + private LocalDateTime dateTime; @BeforeEach public void setup() { gmcId = faker.number().digits(8); + gmcId2 = faker.number().digits(8); responseCode = "0"; localDateTime = LocalDateTime.now(); admin = "admin"; + exceptionReason1 = faker.letterify("aa"); + exceptionReason2 = faker.letterify("bb"); + dateTime = LocalDateTime.now(); initializeExceptionLogList(); } @@ -86,21 +91,18 @@ void shouldCreateExceptionLog() { } @Test - void shouldGetExceptionLog() { - final var exceptionRequestDto = ExceptionRequestDto.builder().pageNumber(1) - .sortOrder("asc").sortColumn("gmcId").build(); - final var pageableAndSortable = PageRequest.of(1, 20, by(ASC, "gmcId")); - when(repository.findAll(pageableAndSortable)).thenReturn(page); - when(page.get()).thenReturn(Stream.of(exceptionLog)); - final var exceptionResponseDto = exceptionService.getExceptionLog(exceptionRequestDto); - assertThat(exceptionResponseDto.getExceptionRecord(), hasSize(1)); - } + void shouldReturnExceptionLogs() { + LocalDateTime todayStart = LocalDate.now().atStartOfDay(); + LocalDateTime tomorrowStart = todayStart.plusDays(1); - @Test - void shouldReturnLogsMap() { - when(repository.findAll()).thenReturn(exceptionLogList); - final var result = exceptionService.getExceptionsMap(); - assertThat(result.get(gmcId), is(responseCode)); + when(repository.findByAdminAndTimestampBetween(admin, todayStart, tomorrowStart)) + .thenReturn(buildExceptionLogList()); + + final var result = exceptionService.getConnectionExceptionLogsFromToday(admin); + assertThat(result.get(0).getGmcId(), is(gmcId)); + assertThat(result.get(0).getAdmin(), is(admin)); + assertThat(result.get(0).getTimestamp(), greaterThan(todayStart)); + assertThat(result.get(0).getTimestamp(), lessThan(tomorrowStart)); } private void initializeExceptionLogList() { @@ -113,4 +115,16 @@ private void initializeExceptionLogList() { exceptionLogList = new ArrayList<>(); exceptionLogList.add(exceptionLog); } + + private List buildExceptionLogList() { + final var record1 = ExceptionLog.builder() + .gmcId(gmcId).errorMessage(exceptionReason1) + .timestamp(dateTime).admin(admin) + .build(); + final var record2 = ExceptionLog.builder() + .gmcId(gmcId2).errorMessage(exceptionReason2) + .timestamp(dateTime).admin(admin) + .build(); + return of(record1, record2); + } }