Skip to content

Commit

Permalink
Staging/seedlots endpoint integration (#662)
Browse files Browse the repository at this point in the history
* Feat/572 integrate seedlot creation (#579)

* fix: refactor class a reg screen

* feat: add default ind to seedlot source table

* feat: error handling and submission complete

* feat: implement feedback page

* fix: update cypres test

* fix: remove outdated ci call

* fix: add japadog

* fix: use string array for old components

* fix: wrong type

* fix: adding CI back

* fix: fix import

* fix: react prop error

* fix: use bool

* fix: mock status code

* Feat/573 integrate get all recent seedlots (#593)

* fix: use user_id instead of name in seedlot table

* fix: refactor seedlot table and more

* feat: table refactor complete

* feat: add 404 and simple redirect

* feat: retrieve seedlot by number

* fix: stage changes

* feat: refactor seedlot detail

* feat: refactor seedlot summary

* fix: use useEffect to populate data

* feat: restyle seedlot detail

* fix: refactor forms

* fix: fix test

* fix: import error

* Declare luxon for types

* fix: misc fixes

* fix: separate render functions

* fix: add hyphen

---------

Co-authored-by: Derek Roberts <[email protected]>

* Feat/595 my seedlot page endpoint integration (#616)

* fix: use user_id instead of name in seedlot table

* fix: refactor seedlot table and more

* feat: table refactor complete

* feat: add 404 and simple redirect

* feat: retrieve seedlot by number

* fix: stage changes

* feat: refactor seedlot detail

* feat: refactor seedlot summary

* fix: use useEffect to populate data

* feat: restyle seedlot detail

* fix: refactor forms

* fix: fix test

* fix: import error

* Declare luxon for types

* fix: misc fixes

* fix: separate render functions

* fix: add hyphen

* feat: modularize seedlot table further

* feat: sorting complete

* feat: search complete

* fix: search bug

* feat: include total count in http header, also fixed service test

* feat: front end detects total count from headers

* feat: pass total count prop

* feat: pagination and styles

* fix: styles

* fix: border style

* fix: remove commented out code

---------

Co-authored-by: Derek Roberts <[email protected]>

* feat: making it work with fam changes

* fix: duplicated id bug

* fix: remove signed props

* fix: dup id

* fix: style

* fix: user new user_id format

* fix: java test

---------

Co-authored-by: Derek Roberts <[email protected]>
  • Loading branch information
craigyu and DerekRoberts committed May 14, 2024
1 parent 8176407 commit 89be43f
Show file tree
Hide file tree
Showing 113 changed files with 2,664 additions and 1,647 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ca.bc.gov.backendstartapi.dto;

import io.swagger.v3.oas.annotations.media.Schema;

/**
* This general record is used for simple data object with only a code and description to be
* consumed by endpoints.
*/
@Schema(description = """
A DTO for seedlot sources.
""")
public record SeedlotSourceDto(
@Schema(description = "The Code that represent a data object", example = "1") String code,
@Schema(description = "The description/value of the data object", example = "Squirrel cache")
String description,
@Schema(description = "Indicate whether this option is default", example = "True")
Boolean isDefault) {}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand Down Expand Up @@ -194,6 +197,7 @@ public ResponseEntity<SeedlotCreateResponseDto> createSeedlot(
* @return A {@link List} of {@link Seedlot} populated or empty
*/
@GetMapping("/users/{userId}")
@CrossOrigin(exposedHeaders = "X-TOTAL-COUNT")
@Operation(
summary = "Fetch all seedlots registered by a given user.",
description = "Returns a paginated list containing the seedlots",
Expand All @@ -206,7 +210,7 @@ public ResponseEntity<SeedlotCreateResponseDto> createSeedlot(
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
public List<Seedlot> getUserSeedlots(
public ResponseEntity<List<Seedlot>> getUserSeedlots(
@PathVariable
@Parameter(
name = "userId",
Expand All @@ -216,7 +220,13 @@ public List<Seedlot> getUserSeedlots(
String userId,
@RequestParam(value = "page", required = false, defaultValue = "0") int page,
@RequestParam(value = "size", required = false, defaultValue = "10") int size) {
return seedlotService.getUserSeedlots(userId, page, size);
Optional<Page<Seedlot>> optionalResult = seedlotService.getUserSeedlots(userId, page, size);
List<Seedlot> result = optionalResult.isEmpty() ? List.of() : optionalResult.get().getContent();
String totalCount =
optionalResult.isEmpty() ? "0" : String.valueOf(optionalResult.get().getTotalElements());
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("X-TOTAL-COUNT", totalCount);
return ResponseEntity.ok().headers(responseHeaders).body(result);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ca.bc.gov.backendstartapi.endpoint;

import ca.bc.gov.backendstartapi.dto.CodeDescriptionDto;
import ca.bc.gov.backendstartapi.dto.SeedlotSourceDto;
import ca.bc.gov.backendstartapi.entity.SeedlotSourceEntity;
import ca.bc.gov.backendstartapi.service.SeedlotSourceService;
import io.swagger.v3.oas.annotations.Operation;
Expand Down Expand Up @@ -61,14 +61,21 @@ public class SeedlotSourceEndpoint {
@Schema(
type = "string",
description = "Name of a seedlot source",
example = "Custom Lot"))
example = "Custom Lot")),
@SchemaProperty(
name = "isDefault",
schema =
@Schema(
type = "boolean",
description = "Indicates if this option is default",
example = "true"))
})),
@ApiResponse(
responseCode = "401",
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
public List<CodeDescriptionDto> getAllSeedlotSource() {
public List<SeedlotSourceDto> getAllSeedlotSource() {
return seedlotSourceService.getAllSeedlotSource();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,19 @@ public class SeedlotSourceEntity extends CodeDescriptionEntity {
@Column(name = "seedlot_source_code", length = 3)
private String seedlotSourceCode;

@Column(name = "default_source_ind", nullable = true)
private Boolean isDefault;

/**
* Constructor for SeedlotSourceEntity.
*/
public SeedlotSourceEntity(
String seedlotSourceCode, String description, EffectiveDateRange effectiveDateRange) {
String seedlotSourceCode,
String description,
EffectiveDateRange effectiveDateRange,
Boolean isDefault) {
super(description, effectiveDateRange);
this.seedlotSourceCode = seedlotSourceCode;
this.isDefault = isDefault;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.backendstartapi.entity.seedlot.Seedlot;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
Expand All @@ -24,5 +25,5 @@ where cast(s.id as int) between ?1 and ?2
* @param pageable the pagination and sorting specifications
* @return A {@link List} of {@link Seedlot} populated or empty
*/
List<Seedlot> findAllByAuditInformation_EntryUserId(String userId, Pageable pageable);
Page<Seedlot> findAllByAuditInformation_EntryUserId(String userId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ public Optional<UserInfo> getUserInfo() {
lastName = displayName.substring(indexFirstSpace).trim();
}

// User id (@idir or @bceid)
String userId = jwtPrincipal.getClaimAsString("cognito:username");
// User id {IDIR@USERNAME}
String cappedUsername = idpUsername.toUpperCase();
String cappedProvider = provider.toUpperCase();
String userId = String.format("%s@%s", cappedProvider, cappedUsername);

// Email will be empty, until next FAM release
String email = jwtPrincipal.getClaimAsString("email");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
import ca.bc.gov.backendstartapi.repository.SeedlotStatusRepository;
import ca.bc.gov.backendstartapi.security.LoggedUserService;
import jakarta.transaction.Transactional;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
Expand Down Expand Up @@ -75,7 +75,7 @@ public SeedlotCreateResponseDto createSeedlot(SeedlotCreateDto createDto) {

seedlot.setIntendedForCrownLand(createDto.toBeRegistrdInd());
seedlot.setSourceInBc(createDto.bcSourceInd());
seedlot.setAuditInformation(new AuditInformation(loggedUserService.getLoggedUserIdirOrBceId()));
seedlot.setAuditInformation(new AuditInformation(loggedUserService.getLoggedUserId()));

log.debug("Seedlot to insert: {}", seedlot);

Expand Down Expand Up @@ -124,15 +124,16 @@ private String nextSeedlotNumber(Character seedlotClassCode) {
* @param pageSize the size of the page
* @return a list of the user's seedlots
*/
public List<Seedlot> getUserSeedlots(String userId, int pageNumber, int pageSize) {
public Optional<Page<Seedlot>> getUserSeedlots(String userId, int pageNumber, int pageSize) {
if (pageSize == 0) {
pageSize = 10;
}

Pageable sortedPageable =
PageRequest.of(
pageNumber, pageSize, Sort.by(Direction.DESC, "AuditInformation_UpdateTimestamp"));
return seedlotRepository.findAllByAuditInformation_EntryUserId(userId, sortedPageable);
return Optional.of(
seedlotRepository.findAllByAuditInformation_EntryUserId(userId, sortedPageable));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ca.bc.gov.backendstartapi.service;

import ca.bc.gov.backendstartapi.dto.CodeDescriptionDto;
import ca.bc.gov.backendstartapi.dto.SeedlotSourceDto;
import ca.bc.gov.backendstartapi.repository.SeedlotSourceRepository;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -18,15 +18,18 @@ public SeedlotSourceService(SeedlotSourceRepository seedlotSourceRepository) {
}

/** Fetch all valid seedlot source from the repository. */
public List<CodeDescriptionDto> getAllSeedlotSource() {
public List<SeedlotSourceDto> getAllSeedlotSource() {
log.info("Fetching all seedlot source");
List<CodeDescriptionDto> resultList = new ArrayList<>();
List<SeedlotSourceDto> resultList = new ArrayList<>();
seedlotSourceRepository.findAll().stream()
.filter(method -> method.isValid())
.forEach(
method -> {
CodeDescriptionDto methodToAdd =
new CodeDescriptionDto(method.getSeedlotSourceCode(), method.getDescription());
SeedlotSourceDto methodToAdd =
new SeedlotSourceDto(
method.getSeedlotSourceCode(),
method.getDescription(),
method.getIsDefault());
resultList.add(methodToAdd);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
alter table
spar.seedlot_source_list
add
default_source_ind boolean default null;

alter table
spar.seedlot_source_list
add
constraint only_one_default_source unique (default_source_ind);

update
spar.seedlot_source_list
set
description = 'Custom Seedlot'
where
seedlot_source_code = 'CUS';

update
spar.seedlot_source_list
set
default_source_ind = true
where
seedlot_source_code = 'TPT';
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.security.test.context.support.WithMockUser;
Expand Down Expand Up @@ -221,9 +223,11 @@ void getUserSeedlotInfoTestDefaultPagination() throws Exception {
List<Seedlot> userSeedlots = new ArrayList<>();
userSeedlots.add(seedlotEntity);

Optional<Page<Seedlot>> pagedResult = Optional.of(new PageImpl<>(userSeedlots));

String url = String.format("/api/seedlots/users/%s", USER_ID);

when(seedlotService.getUserSeedlots(USER_ID, 1, 10)).thenReturn(userSeedlots);
when(seedlotService.getUserSeedlots(USER_ID, 1, 10)).thenReturn(pagedResult);

mockMvc
.perform(get(url).accept(MediaType.APPLICATION_JSON))
Expand All @@ -239,15 +243,14 @@ void getUserSeedlotInfoTestChangePageNumber() throws Exception {
List<Seedlot> userSeedlots = new ArrayList<>();
userSeedlots.add(seedlotEntity);

when(seedlotService.getUserSeedlots(USER_ID, 1, 10)).thenReturn(userSeedlots);
Optional<Page<Seedlot>> pagedResult = Optional.of(new PageImpl<>(userSeedlots));
when(seedlotService.getUserSeedlots(USER_ID, 1, 10)).thenReturn(pagedResult);

String url = String.format("/api/seedlots/users/%s?page={page}", USER_ID);
int page = 1;

mockMvc
.perform(
get(url, page)
.accept(MediaType.APPLICATION_JSON))
.perform(get(url, page).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
}
Expand All @@ -264,12 +267,11 @@ void getUserSeedlotInfoTestChangePageSize() throws Exception {
String url = String.format("/api/seedlots/users/%s?page=1&size={size}", USER_ID);
int pageSize = 2;

when(seedlotService.getUserSeedlots(USER_ID, 1, pageSize)).thenReturn(userSeedlots);
Optional<Page<Seedlot>> pagedResult = Optional.of(new PageImpl<>(userSeedlots));
when(seedlotService.getUserSeedlots(USER_ID, 1, pageSize)).thenReturn(pagedResult);

mockMvc
.perform(
get(url, pageSize)
.accept(MediaType.APPLICATION_JSON))
.perform(get(url, pageSize).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.length()").value(2))
.andReturn();
Expand All @@ -278,7 +280,9 @@ void getUserSeedlotInfoTestChangePageSize() throws Exception {
@Test
@DisplayName("getSingleSeedlotInfoNotFoundNoPageTest")
void getSingleSeedlotInfoNotFoundNoPageTest() throws Exception {
when(seedlotService.getUserSeedlots(USER_ID, 1, 10)).thenReturn(List.of());

Optional<Page<Seedlot>> pagedResult = Optional.of(new PageImpl<>(List.of()));
when(seedlotService.getUserSeedlots(USER_ID, 1, 10)).thenReturn(pagedResult);

String url = String.format("/api/seedlots/users/%s", USER_ID);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import ca.bc.gov.backendstartapi.dto.CodeDescriptionDto;
import ca.bc.gov.backendstartapi.dto.SeedlotSourceDto;
import ca.bc.gov.backendstartapi.service.SeedlotSourceService;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
Expand Down Expand Up @@ -37,9 +37,9 @@ class SeedlotSourceEndpointTest {
@WithMockUser(roles = "user_read")
void getAllSeedlotSource() throws Exception {

CodeDescriptionDto firstMethod = new CodeDescriptionDto("CUS", "Custom Lot");
CodeDescriptionDto secondMethod = new CodeDescriptionDto("TPT", "Tested Parent Trees");
CodeDescriptionDto thirdMethod = new CodeDescriptionDto("UPT", "Untested Parent Trees");
SeedlotSourceDto firstMethod = new SeedlotSourceDto("CUS", "Custom Lot", null);
SeedlotSourceDto secondMethod = new SeedlotSourceDto("TPT", "Tested Parent Trees", true);
SeedlotSourceDto thirdMethod = new SeedlotSourceDto("UPT", "Untested Parent Trees", null);

when(seedlotSourceService.getAllSeedlotSource())
.thenReturn(List.of(firstMethod, secondMethod, thirdMethod));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ protected Seedlot createSeedlot(String id) {
new GeneticWorthEntity("AD", "Animal browse resistance (deer)", effectiveDateRange);
geneticWorthRepository.saveAndFlush(geneticWorth);


var seedlotSource = new SeedlotSourceEntity("CUS", "Custom Lot", effectiveDateRange);
var seedlotSource = new SeedlotSourceEntity("CUS", "Custom Lot", effectiveDateRange, null);
seedlotSourceRepository.saveAndFlush(seedlotSource);

var seedlot = new Seedlot(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ void getUserInfoIdirTest() {
builder.claim("custom:idp_display_name", "Baggings, Bilbo LWRS:EX");
builder.claim("custom:idp_username", "BAGGINGS");
builder.claim("custom:idp_name", "idir");
builder.claim("cognito:username", "abcdefg123465789@idir");
builder.claim("cognito:username", "IDIR@BAGGINGS");

when(authentication.getPrincipal()).thenReturn(builder.build());

Optional<UserInfo> userInfoOptional = userAuthenticationHelper.getUserInfo();
Assertions.assertTrue(userInfoOptional.isPresent());

UserInfo userInfo = userInfoOptional.get();
Assertions.assertEquals("abcdefg123465789@idir", userInfo.id());
Assertions.assertEquals("IDIR@BAGGINGS", userInfo.id());
Assertions.assertEquals("Bilbo", userInfo.firstName());
Assertions.assertEquals("Baggings", userInfo.lastName());
Assertions.assertEquals("[email protected]", userInfo.email());
Expand All @@ -78,15 +78,15 @@ void getUserInfoBusinessBceidTest() {
builder.claim("custom:idp_display_name", "Lord Sauron of Mordor");
builder.claim("custom:idp_username", "MORDOR-BCEID");
builder.claim("custom:idp_name", "bceidbusiness");
builder.claim("cognito:username", "abcdefg123465789@bceid");
builder.claim("cognito:username", "BCEIDBUSINESS@MORDOR-BCEID");

when(authentication.getPrincipal()).thenReturn(builder.build());

Optional<UserInfo> userInfoOptional = userAuthenticationHelper.getUserInfo();
Assertions.assertTrue(userInfoOptional.isPresent());

UserInfo userInfo = userInfoOptional.get();
Assertions.assertEquals("abcdefg123465789@bceid", userInfo.id());
Assertions.assertEquals("BCEIDBUSINESS@MORDOR-BCEID", userInfo.id());
Assertions.assertEquals("Lord", userInfo.firstName());
Assertions.assertEquals("Sauron of Mordor", userInfo.lastName());
Assertions.assertEquals("[email protected]", userInfo.email());
Expand Down
Loading

0 comments on commit 89be43f

Please sign in to comment.