Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement profile management on oracle #1080

Merged
merged 27 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6ba930a
feat: create interceptor to validate roles and access levels
Apr 24, 2024
c5e4107
feat: rbac interceptor ready
Apr 25, 2024
646097d
feat: add role-based access control to C* endpoints
Apr 26, 2024
3abb232
feat: add role-based access control to F* endpoints
Apr 26, 2024
f1be28a
chore: fix checkstyle, refactor to better naming
Apr 26, 2024
f05ecdf
feat: add role-based access control to G* endpoints
Apr 26, 2024
4a55d9e
feat: add role-based access control to L* endpoints
Apr 26, 2024
4438ee1
feat: add role-based access control to M* endpoints
Apr 26, 2024
7524fd2
feat: add role-based access control to O* endpoints
Apr 26, 2024
5e2538c
feat: add role-based access control to P* endpoints
Apr 26, 2024
45327ea
feat: add role-based access control to S* endpoints
Apr 26, 2024
d4344ac
feat: add role-based access control to T* endpoints
Apr 26, 2024
f0e5d5c
chore: refactor to avoid mistakes between strings and single chars
Apr 26, 2024
2b7dacc
test: fix test cases with proper role
Apr 29, 2024
1f76c50
Merge branch 'main' into feat/879-implement-profile-management-and-re…
Apr 29, 2024
a586ab3
Merge branch 'main' into feat/879-implement-profile-management-and-re…
Apr 30, 2024
a2f7c28
chore: remove duplication and add more tests
Apr 30, 2024
4897612
test: add corner cases tests
Apr 30, 2024
c53c1b3
Merge branch 'main' into feat/879-implement-profile-management-and-re…
Apr 30, 2024
48226ec
feat: add rbac to oracle endpoints
Apr 30, 2024
abcabfc
Merge branch 'main' into feat/879-implement-profile-management-and-re…
Apr 30, 2024
5c1e97a
feat: remove duplication on role security config
Apr 30, 2024
81797f8
feat: simplify roles config
May 7, 2024
8cdf8b1
feat: simplify role based access control
May 7, 2024
6d1cc7c
docs: fix java docs
May 7, 2024
91944d0
Merge branch 'main' into feat/879-implement-profile-management-and-re…
May 7, 2024
c2e779a
Merge branch 'feat/879-implement-profile-management-and-restrictions'…
May 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
sonar_args:
-Dsonar.organization=bcgov-sonarcloud -Dsonar.projectKey=nr-spar_${{ matrix.dir }}
-Dsonar.coverage.jacoco.xmlReportPaths=target/coverage-reports/merged-test-report/jacoco.xml
-Dsonar.exclusions=**/config/**,*/dto/**,**/entity/**,**/exception/**,**/response/**,**/**Builder*,**/RestExceptionEndpoint.*,**/BackendStartApiApplication.*
-Dsonar.exclusions=**/config/**,*/dto/**,**/entity/**,**/exception/**,**/filter/**,**/interceptor/**,**/response/**,**/**Builder*,**/RestExceptionEndpoint.*,**/BackendStartApiApplication.*
sonar_token: ${{ secrets[matrix.token] }}

codeql:
Expand Down
1 change: 1 addition & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@
<exclude>**/entity/**</exclude>
<exclude>**/exception/**</exclude>
<exclude>**/filter/**</exclude>
<exclude>**/interceptor/**</exclude>
<exclude>**/response/**</exclude>
<exclude>**/*$*Builder*</exclude>
<exclude>**/RestExceptionEndpoint.*</exclude>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ca.bc.gov.backendstartapi.config;

import ca.bc.gov.backendstartapi.interceptor.RoleAccessInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/** This class simply add the Crud Matrix interceptor in the request chain. */
@Configuration
public class RoleAccessInterceptorConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(@NonNull InterceptorRegistry registry) {
registry.addInterceptor(new RoleAccessInterceptor());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package ca.bc.gov.backendstartapi.config;

import java.util.ArrayList;
import ca.bc.gov.backendstartapi.security.JwtSecurityUtil;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -75,20 +76,8 @@ private Converter<Jwt, AbstractAuthenticationToken> converter() {
if (!jwt.getClaims().containsKey("cognito:groups")) {
return List.of();
}
Object clientRolesObj = jwt.getClaims().get("cognito:groups");
final List<String> realmAccess = new ArrayList<>();
if (clientRolesObj instanceof List<?> list) {
for (Object item : list) {
String role = String.valueOf(item);
// Removes Client Number
String clientNumber = role.substring(role.length() - 8);
if (clientNumber.replaceAll("[0-9]", "").isEmpty()) {
role = role.substring(0, role.length() - 9); // Removes dangling underscore
}
realmAccess.add(role);
}
}
return realmAccess.stream()
Set<String> roleSet = JwtSecurityUtil.getUserRolesFromJwt(jwt);
return roleSet.stream()
.map(roleName -> "ROLE_" + roleName)
.map(roleName -> (GrantedAuthority) new SimpleGrantedAuthority(roleName))
.toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.backendstartapi.entity.ActiveOrchardSpuEntity;
import ca.bc.gov.backendstartapi.repository.ActiveOrchardSeedPlanningUnitRepository;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand Down Expand Up @@ -34,6 +35,7 @@ public class ActiveOrchardSeedPlanningUnitEndpoint {
responseCode = "200",
description = "A list of the associations between the orchard and seed plan units.")
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
@GetMapping(path = "/{orchardId}/seed-plan-units")
public List<ActiveOrchardSpuEntity> findByOrchard(
@Parameter(description = "The identifier of an orchard") @PathVariable(name = "orchardId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.backendstartapi.dto.CodeDescriptionDto;
import ca.bc.gov.backendstartapi.entity.ConeCollectionMethodEntity;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.ConeCollectionMethodService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
Expand Down Expand Up @@ -70,6 +71,7 @@ public class ConeCollectionMethodEndpoint {
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<CodeDescriptionDto> getAllConeCollectionMethods() {
return coneCollectionMethodService.getAllConeCollectionMethods();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ca.bc.gov.backendstartapi.config.SparLog;
import ca.bc.gov.backendstartapi.dto.DescribedEnumDto;
import ca.bc.gov.backendstartapi.enums.DescribedEnum;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
Expand Down Expand Up @@ -45,6 +46,7 @@ interface DescribedEnumEndpoint<E extends Enum<E> & DescribedEnum> {
responseCode = "200",
description = "A list of all the codes and their descriptions.")
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
default ResponseEntity<List<DescribedEnumDto<E>>> fetchAll() {
String simpleName = enumClass().getSimpleName();
SparLog.info("Fetching all codes and descriptions for {} class", simpleName);
Expand All @@ -69,6 +71,7 @@ default ResponseEntity<List<DescribedEnumDto<E>>> fetchAll() {
description = "No code was found",
content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
default ResponseEntity<DescribedEnumDto<E>> fetch(
@Parameter(description = "The code to be fetched.") @PathVariable("code") String code) {
SparLog.info(
Expand All @@ -82,8 +85,7 @@ default ResponseEntity<DescribedEnumDto<E>> fetch(
.map(DescribedEnumDto::new);
String simpleName = enumClass().getSimpleName();
valueDto.ifPresent(
values ->
SparLog.info("Record for code {} found in class {}", code, simpleName));
values -> SparLog.info("Record for code {} found in class {}", code, simpleName));
if (valueDto.isEmpty()) {
SparLog.warn("Record for code {} not found in class {}", code, simpleName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import ca.bc.gov.backendstartapi.entity.FavouriteActivityEntity;
import ca.bc.gov.backendstartapi.response.DefaultSpringExceptionResponse;
import ca.bc.gov.backendstartapi.response.ValidationExceptionResponse;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.FavouriteActivityService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -80,6 +81,7 @@ public class FavouriteActivityEndpoint {
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public ResponseEntity<FavouriteActivityEntity> createUserActivity(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "Body containing the activity name that will be created",
Expand Down Expand Up @@ -118,6 +120,7 @@ public ResponseEntity<FavouriteActivityEntity> createUserActivity(
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<FavouriteActivityEntity> getUserActivities() {
return favouriteActivityService.getAllUserFavoriteActivities();
}
Expand Down Expand Up @@ -153,6 +156,7 @@ public List<FavouriteActivityEntity> getUserActivities() {
description = "The FavouriteActivityEntity was not found",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public FavouriteActivityEntity updateFavoriteActivity(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "Body containing the activity enabled and highlighted property values",
Expand Down Expand Up @@ -197,6 +201,7 @@ public FavouriteActivityEntity updateFavoriteActivity(
description = "The FavouriteActivityEntity was not found",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public void deleteFavoriteActivity(
@Parameter(
name = "id",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ca.bc.gov.backendstartapi.dto.ForestClientDto;
import ca.bc.gov.backendstartapi.dto.ForestClientLocationDto;
import ca.bc.gov.backendstartapi.dto.ForestClientSearchDto;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.ForestClientService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -58,6 +59,7 @@ public class ForestClientEndpoint {
content = @Content(schema = @Schema(implementation = ForestClientDto.class))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public ResponseEntity<Serializable> fetchClient(
@PathVariable("identifier")
@Pattern(regexp = "^\\d{8}$|^\\w{1,8}$")
Expand Down Expand Up @@ -92,6 +94,7 @@ public ResponseEntity<Serializable> fetchClient(
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<ForestClientLocationDto> fetchClientLocations(
@PathVariable("clientNumber")
@Pattern(regexp = "^\\d{8}$", message = "The value must be an 8-digit number")
Expand Down Expand Up @@ -129,6 +132,7 @@ public List<ForestClientLocationDto> fetchClientLocations(
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public ForestClientLocationDto fetchSingleClientLocation(
@PathVariable("clientNumber")
@Pattern(regexp = "^\\d{8}$", message = "The value must be an 8-digit number")
Expand All @@ -146,16 +150,23 @@ public ForestClientLocationDto fetchSingleClientLocation(
return forestClientService.fetchSingleClientLocation(clientNumber, locationCode);
}

/**
* Searchs for clients given a type and a query term.
*
* @param type One of: [acronym | client_number | client_name].
* @param query The term to be searched for.
* @return A list of {@link ForestClientSearchDto} containing the result.
*/
@GetMapping(path = "/search")
@Operation(
summary = "",
description = """
""",
summary = "Searchs for clients given a type and a query term",
description = "Allows searching for Forest Clients given a type and a search term",
responses = {
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "400"),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<ForestClientSearchDto> searchForestClients(
@RequestParam(defaultValue = "acronym")
@Parameter(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ca.bc.gov.backendstartapi.endpoint;

import ca.bc.gov.backendstartapi.dto.GameticMethodologyDto;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.GameticMethodologyService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
Expand Down Expand Up @@ -89,6 +90,7 @@ The code field starts with a character (M/F) that indicate the sex of
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<GameticMethodologyDto> getAllMaleFemaleMethodologies() {
return gameticMethodologyService.getAllGameticMethodologies();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.backendstartapi.dto.CodeDescriptionDto;
import ca.bc.gov.backendstartapi.entity.GeneticClassEntity;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.GeneticClassService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -72,6 +73,7 @@ public class GeneticClassEndpoint {
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<CodeDescriptionDto> getAllGeneticClass() {
return geneticClassService.getAllGeneticClass();
}
Expand All @@ -95,6 +97,7 @@ public List<CodeDescriptionDto> getAllGeneticClass() {
content = @Content(schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public CodeDescriptionDto getOrchardById(
@PathVariable
@Parameter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.backendstartapi.dto.CodeDescriptionDto;
import ca.bc.gov.backendstartapi.entity.GeneticWorthEntity;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.GeneticWorthService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -72,6 +73,7 @@ public class GeneticWorthEndpoint {
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<CodeDescriptionDto> getAllGeneticWorth() {
return geneticWorthService.getAllGeneticWorth();
}
Expand All @@ -95,6 +97,7 @@ public List<CodeDescriptionDto> getAllGeneticWorth() {
content = @Content(schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public CodeDescriptionDto getGeneticWorthByCode(
@PathVariable
@Parameter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.backendstartapi.dto.MethodOfPaymentDto;
import ca.bc.gov.backendstartapi.entity.MethodOfPaymentEntity;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.MethodOfPaymentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
Expand Down Expand Up @@ -68,6 +69,7 @@ public class MethodOfPaymentEndpoint {
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<MethodOfPaymentDto> getAllMethodOfPayment() {
return methodOfPaymentService.getAllMethodOfPayment();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ca.bc.gov.backendstartapi.dto.OrchardSpuDto;
import ca.bc.gov.backendstartapi.dto.ParentTreeDto;
import ca.bc.gov.backendstartapi.dto.SameSpeciesTreeDto;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.OrchardService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -54,6 +55,7 @@ public class OrchardEndpoint {
content = @Content(schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public OrchardSpuDto getParentTreeGeneticQualityData(
@PathVariable
@Parameter(
Expand Down Expand Up @@ -85,6 +87,7 @@ public OrchardSpuDto getParentTreeGeneticQualityData(
content = @Content(schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<OrchardDto> getOrchardsByVegCode(
@PathVariable("vegCode")
@Pattern(regexp = "^[a-zA-Z]{1,8}$")
Expand Down Expand Up @@ -120,6 +123,7 @@ public List<OrchardDto> getOrchardsByVegCode(
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public List<SameSpeciesTreeDto> getAllParentTreeByVegCode(
@PathVariable("vegCode")
@Pattern(regexp = "^[a-zA-Z]{1,8}$")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ca.bc.gov.backendstartapi.dto.PtValsCalReqDto;
import ca.bc.gov.backendstartapi.response.DefaultSpringExceptionResponse;
import ca.bc.gov.backendstartapi.response.ValidationExceptionResponse;
import ca.bc.gov.backendstartapi.security.RoleAccessConfig;
import ca.bc.gov.backendstartapi.service.ParentTreeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
Expand Down Expand Up @@ -66,6 +67,7 @@ public class ParentTreeEndpoint {
description = "Access token is missing or invalid",
content = @Content(schema = @Schema(implementation = Void.class)))
})
@RoleAccessConfig({"SPAR_TSC_ADMIN", "SPAR_MINISTRY_ORCHARD", "SPAR_NONMINISTRY_ORCHARD"})
public PtCalculationResDto parentTreeValsCalculation(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "Body containing the traits and values to be used in the calculations",
Expand Down
Loading