Skip to content
This repository has been archived by the owner on May 3, 2023. It is now read-only.

Commit

Permalink
feat: funding source API (#78)
Browse files Browse the repository at this point in the history
* feat: add funding source endpoint, repository, entity and endpoint test

* tests: add funding source repository test

* docs: add javadoc notes

* ci: autogenerated JaCoCo coverage badge

* docs: add open api documentation

* feat: use date filters in the query instead of the code

* ci: autogenerated JaCoCo coverage badge

* tests: improve test cases to validate expiry and effective dates

* feat: update to use JPQL

This update changes from native query to use Jakarta Persistence Query Language

* tests: update valid condition to include better description and test case

---------

Co-authored-by: Ci Bot <cibot@users.noreply.github.com>
  • Loading branch information
Ricardo Campos and Ci Bot authored Feb 22, 2023
1 parent c39f98f commit 02c251c
Showing 7 changed files with 298 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package ca.bc.gov.backendstartapi.endpoint;

import ca.bc.gov.backendstartapi.entity.FundingSource;
import ca.bc.gov.backendstartapi.repository.FundingSourceRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.time.LocalDate;
import java.time.temporal.TemporalUnit;
import java.util.List;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/** This class exposes funding sources resources API. */
@Setter
@RestController
@NoArgsConstructor
@RequestMapping("/api/funding-sources")
@Tag(
name = "FundingSourceEndpoint",
description = "Resource to retrieve Funding Source to Owners Agencies")
public class FundingSourceEndpoint {

private FundingSourceRepository fundingSourceRepository;

@Autowired
public FundingSourceEndpoint(FundingSourceRepository fundingSourceRepository) {
this.fundingSourceRepository = fundingSourceRepository;
}

/**
* Retrieve all funding sources.
*
* @return A list of {@link FundingSource} with all found result.
*/
@GetMapping(produces = "application/json")
@PreAuthorize("hasRole('user_read')")
@Operation(
summary = "Retrieve non-expired funding sources",
description = "Retrieve all valid (non expired) funding source based on effectiveDate "
+ "and expiryDate, where 'today >= effectiveDate' and 'today < expiryDate'.")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "Returns a list containing all valid (non expired) funding sources",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = FundingSource.class))),
@ApiResponse(
responseCode = "401",
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
public List<FundingSource> getAllValidFundingSources() {
return fundingSourceRepository.findAllValid();
}
}
44 changes: 44 additions & 0 deletions src/main/java/ca/bc/gov/backendstartapi/entity/FundingSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ca.bc.gov.backendstartapi.entity;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.time.LocalDate;
import lombok.Getter;
import lombok.Setter;

/** This class presents a funding source to an agency seedlot owner. */
@Getter
@Setter
@Entity
@Table(name = "SPAR_FUND_SRCE_CODE")
@Schema(description = "Represents a Funding Source object in the database")
public class FundingSource {

@Id
@Column(name = "SPAR_FUND_SRCE_CODE")
@Schema(description = "Funding source's code, from SPAR_FUND_SRCE_CODE column", example = "BCT")
private String code;

@Column(name = "DESCRIPTION")
@Schema(
description = "Funding source's description, from DESCRIPTION column",
example = "BC Timber Sales")
private String description;

@Column(name = "EFFECTIVE_DATE")
@Schema(
description = "Funding source's effective date.",
type = "string",
format = "date")
private LocalDate effectiveDate;

@Column(name = "EXPIRY_DATE")
@Schema(
description = "Funding source's expiry date.",
type = "string",
format = "date")
private LocalDate expiryDate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ca.bc.gov.backendstartapi.repository;

import ca.bc.gov.backendstartapi.entity.FundingSource;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

/** This interface enables the funding source entity to be retrieved from the database. */
public interface FundingSourceRepository extends JpaRepository<FundingSource, String> {

@Query(
value =
"select fs from FundingSource fs WHERE CURRENT_DATE >= fs.effectiveDate "
+ "AND CURRENT_DATE < fs.expiryDate ORDER BY fs.code")
List<FundingSource> findAllValid();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package ca.bc.gov.backendstartapi.endpoint;

import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
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 ca.bc.gov.backendstartapi.entity.FundingSource;
import ca.bc.gov.backendstartapi.repository.FundingSourceRepository;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
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.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;

@ExtendWith(SpringExtension.class)
@WebMvcTest(FundingSourceEndpoint.class)
class FundingSourceEndpointTest {

@Autowired private MockMvc mockMvc;

@MockBean private FundingSourceRepository fundingSourceRepository;

@Test
@DisplayName("findAllSuccessTest")
@WithMockUser(roles = "user_read")
void findAllSuccessTest() throws Exception {
FundingSource fundingSourceBct = new FundingSource();
fundingSourceBct.setCode("BCT");
fundingSourceBct.setDescription("BC Timber Sales");
fundingSourceBct.setEffectiveDate(LocalDate.parse("2003-04-01"));
fundingSourceBct.setExpiryDate(LocalDate.parse("9999-12-31"));

FundingSource fundingSourceCbi = new FundingSource();
fundingSourceCbi.setCode("CBI");
fundingSourceCbi.setDescription("Carbon Offset Investment");
fundingSourceCbi.setEffectiveDate(LocalDate.parse("2013-08-01"));
fundingSourceCbi.setExpiryDate(LocalDate.parse("9999-12-31"));

FundingSource fundingSourceCl = new FundingSource();
fundingSourceCl.setCode("CL");
fundingSourceCl.setDescription("Catastrophic Losses");
fundingSourceCl.setEffectiveDate(LocalDate.parse("1905-01-01"));
fundingSourceCl.setExpiryDate(LocalDate.parse("2099-09-30"));

List<FundingSource> sources = new ArrayList<>();
sources.add(fundingSourceBct);
sources.add(fundingSourceCbi);
sources.add(fundingSourceCl);

when(fundingSourceRepository.findAllValid()).thenReturn(sources);

mockMvc
.perform(
get("/api/funding-sources")
.with(csrf().asHeader())
.header("Content-Type", "application/json")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].code").value("BCT"))
.andExpect(jsonPath("$[0].description").value("BC Timber Sales"))
.andExpect(jsonPath("$[0].effectiveDate").value("2003-04-01"))
.andExpect(jsonPath("$[0].expiryDate").value("9999-12-31"))
.andExpect(jsonPath("$[1].code").value("CBI"))
.andExpect(jsonPath("$[1].description").value("Carbon Offset Investment"))
.andExpect(jsonPath("$[1].effectiveDate").value("2013-08-01"))
.andExpect(jsonPath("$[1].expiryDate").value("9999-12-31"))
.andExpect(jsonPath("$[2].code").value("CL"))
.andExpect(jsonPath("$[2].description").value("Catastrophic Losses"))
.andExpect(jsonPath("$[2].effectiveDate").value("1905-01-01"))
.andExpect(jsonPath("$[2].expiryDate").value("2099-09-30"))
.andReturn();
}

@Test
@DisplayName("findAllNoAuthorizedTest")
void findAllNoAuthorizedTest() throws Exception {
mockMvc
.perform(
get("/api/funding-sources")
.with(csrf().asHeader())
.header("Content-Type", "application/json")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is(401))
.andReturn();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package ca.bc.gov.backendstartapi.repository;

import ca.bc.gov.backendstartapi.entity.FundingSource;
import java.time.LocalDate;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class FundingSourceRepositoryTest {

@Autowired private FundingSourceRepository fundingSourceRepository;

private boolean isValid(FundingSource fundingSource) {
LocalDate today = LocalDate.now();

// Effective date - Should be before or same as today
if (fundingSource.getEffectiveDate().isAfter(today)) {
return false;
}

// Expiry date - Should be after today
return fundingSource.getExpiryDate().isAfter(today);
}

@Test
@DisplayName("findAllTest")
@Sql(scripts = {"classpath:scripts/FundingSourceRepositoryTest_findAllTest.sql"})
void findAllTest() {
List<FundingSource> sources = fundingSourceRepository.findAllValid();

Assertions.assertFalse(sources.isEmpty());
Assertions.assertEquals(3, sources.size());

FundingSource fundingSourceBct = sources.get(0);
Assertions.assertEquals("BCT", fundingSourceBct.getCode());
Assertions.assertEquals("BC Timber Sales", fundingSourceBct.getDescription());
Assertions.assertTrue(isValid(fundingSourceBct));

FundingSource fundingSourceCbi = sources.get(1);
Assertions.assertEquals("CBI", fundingSourceCbi.getCode());
Assertions.assertEquals("Carbon Offset Investment", fundingSourceCbi.getDescription());
Assertions.assertTrue(isValid(fundingSourceCbi));

FundingSource fundingSourceCl = sources.get(2);
Assertions.assertEquals("CL", fundingSourceCl.getCode());
Assertions.assertEquals("Catastrophic Losses", fundingSourceCl.getDescription());
Assertions.assertTrue(isValid(fundingSourceCl));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
INSERT INTO SPAR_FUND_SRCE_CODE (SPAR_FUND_SRCE_CODE, DESCRIPTION, EFFECTIVE_DATE, EXPIRY_DATE)
VALUES ('BCT', 'BC Timber Sales', '2003-04-01', '9999-12-31');
INSERT INTO SPAR_FUND_SRCE_CODE (SPAR_FUND_SRCE_CODE, DESCRIPTION, EFFECTIVE_DATE, EXPIRY_DATE)
VALUES ('CBI', 'Carbon Offset Investment', '2013-08-01', '9999-12-31');
INSERT INTO SPAR_FUND_SRCE_CODE (SPAR_FUND_SRCE_CODE, DESCRIPTION, EFFECTIVE_DATE, EXPIRY_DATE)
VALUES ('CL', 'Catastrophic Losses', '1905-01-01', '2099-09-30');

-- Not effective yet
INSERT INTO SPAR_FUND_SRCE_CODE (SPAR_FUND_SRCE_CODE, DESCRIPTION, EFFECTIVE_DATE, EXPIRY_DATE)
VALUES ('CI', 'Catastrophic Issues', '2033-01-01', '2099-09-30');
-- Expired
INSERT INTO SPAR_FUND_SRCE_CODE (SPAR_FUND_SRCE_CODE, DESCRIPTION, EFFECTIVE_DATE, EXPIRY_DATE)
VALUES ('CO', 'Catastrophic Others', '2002-01-01', '2022-09-30');

0 comments on commit 02c251c

Please sign in to comment.