Skip to content

Commit

Permalink
[MODFQMMGR-625] Aggregate dropdown values from all tenants in ECS env…
Browse files Browse the repository at this point in the history
…ironments (#575)
  • Loading branch information
bvsharp authored Jan 9, 2025
1 parent e644f8c commit 630ba3a
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 25 deletions.
28 changes: 28 additions & 0 deletions src/main/java/org/folio/fqm/client/CrossTenantHttpClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.folio.fqm.client;

import org.folio.fqm.config.CrossTenantFeignConfig;
import org.folio.spring.integration.XOkapiHeaders;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;

import java.util.Map;

@Service
@FeignClient(name = "cross-tenant-http-client", url = ".", configuration = CrossTenantFeignConfig.class)
public interface CrossTenantHttpClient {
/**
* Retrieve arbitrary data from a FOLIO API endpoint for the specified tenant.
* @param path - the path of the API endpoint
* @param queryParams - a map of query parameters to pass to the API endpoint
* @param tenant - FOLIO tenant from which to retrieve data
* @return the body of the response (JSON)
*/
@GetMapping(value = "/{path}", produces = MediaType.APPLICATION_JSON_VALUE)
String get(@PathVariable String path, @SpringQueryMap Map<String, String> queryParams, @RequestHeader(XOkapiHeaders.TENANT) String tenant);
}
15 changes: 1 addition & 14 deletions src/main/java/org/folio/fqm/client/SimpleHttpClient.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package org.folio.fqm.client;

import org.folio.spring.integration.XOkapiHeaders;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;

import java.util.Map;

Expand All @@ -16,22 +14,11 @@
public interface SimpleHttpClient {
/**
* Retrieve arbitrary data from a FOLIO API endpoint.
*
* @param path - the path of the API endpoint
* @param queryParams - a map of query parameters to pass to the API endpoint
* @return the body of the response (JSON)
*/
@GetMapping(value = "/{path}", produces = MediaType.APPLICATION_JSON_VALUE)
String get(@PathVariable String path, @SpringQueryMap Map<String, String> queryParams);
/**
* Retrieve arbitrary data from a FOLIO API endpoint for the specified tenant.
*
* @param path - the path of the API endpoint
* @param queryParams - a map of query parameters to pass to the API endpoint
* @param tenant - FOLIO tenant from which to retrieve data
* @return the body of the response (JSON)
*/
@GetMapping(value = "/{path}", produces = MediaType.APPLICATION_JSON_VALUE)
String get(@PathVariable String path, @SpringQueryMap Map<String, String> queryParams, @RequestHeader(XOkapiHeaders.TENANT) String tenant);
String get(@PathVariable String path, @SpringQueryMap Map<String, String> queryParams);
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ public class DataRefreshRepository {
);

private final DSLContext jooqContext;

private final SimpleHttpClient simpleHttpClient;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ private List<String> getTenants(EntityType entityType, UUID userId) {
} catch (MissingPermissionsException e) {
log.info("User with id {} does not have permissions to query tenant {}. Skipping.", currentUserId, tenantId);
} catch (FeignException e) {
log.error("Error retrieving permissions for user ID %s in tenant %s".formatted(currentUserId, tenantId), e);
throw e;
log.error("Error retrieving permissions for user ID %s in tenant %s. Skipping.".formatted(currentUserId, tenantId), e);
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/folio/fqm/service/EntityTypeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.codehaus.plexus.util.StringUtils;
import org.folio.fql.model.field.FqlField;
import org.folio.fql.service.FqlValidationService;
import org.folio.fqm.client.CrossTenantHttpClient;
import org.folio.fqm.client.LanguageClient;
import org.folio.fqm.client.SimpleHttpClient;
import org.folio.fqm.domain.dto.EntityTypeSummary;
Expand Down Expand Up @@ -59,6 +60,7 @@ public class EntityTypeService {
private final LocalizationService localizationService;
private final QueryProcessorService queryService;
private final SimpleHttpClient simpleHttpClient;
private final CrossTenantHttpClient crossTenantHttpClient;
private final PermissionsService permissionsService;
private final CrossTenantQueryService crossTenantQueryService;
private final LanguageClient languageClient;
Expand Down Expand Up @@ -199,7 +201,7 @@ private ColumnValues getFieldValuesFromApi(Field field, String searchText, List<
Set<ValueWithLabel> resultSet = new HashSet<>();
for (String tenantId : tenantsToQuery) {
try {
String rawJson = simpleHttpClient.get(field.getValueSourceApi().getPath(), Map.of("limit", String.valueOf(COLUMN_VALUE_DEFAULT_PAGE_SIZE)), tenantId);
String rawJson = crossTenantHttpClient.get(field.getValueSourceApi().getPath(), Map.of("limit", String.valueOf(COLUMN_VALUE_DEFAULT_PAGE_SIZE)), tenantId);
DocumentContext parsedJson = JsonPath.parse(rawJson);
List<String> values = parsedJson.read(field.getValueSourceApi().getValueJsonPath());
List<String> labels = parsedJson.read(field.getValueSourceApi().getLabelJsonPath());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.folio.fqm.service;

import feign.FeignException;
import org.folio.fqm.client.SimpleHttpClient;
import org.folio.fqm.exception.MissingPermissionsException;
import org.folio.querytool.domain.dto.EntityType;
Expand Down Expand Up @@ -78,6 +79,12 @@ class CrossTenantQueryServiceTest {
"userId": "a5e7895f-503c-4335-8828-f507bc8d1c45",
"tenantId": "tenant_03",
"centralTenantId": "tenant_01"
},
{
"id": "b167837a-ecdd-482b-b5d3-79a391a1dbf1",
"userId": "a5e7895f-503c-4335-8828-f507bc8d1c45",
"tenantId": "tenant_04",
"centralTenantId": "tenant_01"
}
]
}
Expand All @@ -98,7 +105,7 @@ void setup() {
@Test
void shouldGetListOfTenantsToQuery() {
String tenantId = "tenant_01";
List<String> expectedTenants = List.of("tenant_01", "tenant_02", "tenant_03");
List<String> expectedTenants = List.of("tenant_01", "tenant_02", "tenant_03", "tenant_04");

when(executionContext.getTenantId()).thenReturn(tenantId);
when(userTenantService.getUserTenantsResponse(tenantId)).thenReturn(ECS_TENANT_INFO);
Expand Down Expand Up @@ -175,6 +182,7 @@ void shouldNotQueryTenantIfUserLacksTenantPermissions() {
when(ecsClient.get(eq("consortia/bdaa4720-5e11-4632-bc10-d4455cf252df/user-tenants"), anyMap())).thenReturn(USER_TENANT_JSON);
doNothing().when(permissionsService).verifyUserHasNecessaryPermissions("tenant_02", entityType, userId, true);
doThrow(MissingPermissionsException.class).when(permissionsService).verifyUserHasNecessaryPermissions("tenant_03", entityType, userId, true);
doThrow(FeignException.class).when(permissionsService).verifyUserHasNecessaryPermissions("tenant_04", entityType, userId, true);
List<String> actualTenants = crossTenantQueryService.getTenantsToQuery(entityType);
assertEquals(expectedTenants, actualTenants);
}
Expand All @@ -197,7 +205,7 @@ void shouldQueryCentralTenantForSharedCompositeInstances() {
@Test
void shouldGetListOfTenantsToQueryForColumnValues() {
String tenantId = "tenant_01";
List<String> expectedTenants = List.of("tenant_01", "tenant_02", "tenant_03");
List<String> expectedTenants = List.of("tenant_01", "tenant_02", "tenant_03", "tenant_04");

when(executionContext.getTenantId()).thenReturn(tenantId);
when(userTenantService.getUserTenantsResponse(tenantId)).thenReturn(ECS_TENANT_INFO);
Expand All @@ -211,7 +219,7 @@ void shouldGetListOfTenantsToQueryForColumnValues() {
void shouldGetListOfTenantsToQueryForSpecifiedUser() {
String tenantId = "tenant_01";
UUID userId = UUID.randomUUID();
List<String> expectedTenants = List.of("tenant_01", "tenant_02", "tenant_03");
List<String> expectedTenants = List.of("tenant_01", "tenant_02", "tenant_03", "tenant_04");

when(executionContext.getTenantId()).thenReturn(tenantId);
when(userTenantService.getUserTenantsResponse(tenantId)).thenReturn(ECS_TENANT_INFO);
Expand Down
11 changes: 8 additions & 3 deletions src/test/java/org/folio/fqm/service/EntityTypeServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.folio.fqm.service;

import feign.FeignException;
import org.folio.fqm.client.CrossTenantHttpClient;
import org.folio.fqm.client.LanguageClient;
import org.folio.fqm.client.SimpleHttpClient;
import org.folio.fqm.repository.EntityTypeRepository;
Expand Down Expand Up @@ -48,6 +49,9 @@ class EntityTypeServiceTest {
@Mock
private SimpleHttpClient simpleHttpClient;

@Mock
private CrossTenantHttpClient crossTenantHttpClient;

@Mock
private PermissionsService permissionsService;

Expand Down Expand Up @@ -350,7 +354,7 @@ void shouldReturnValuesFromApi() {

when(crossTenantQueryService.getTenantsToQueryForColumnValues(entityType)).thenReturn(tenantList);
when(entityTypeFlatteningService.getFlattenedEntityType(entityTypeId, null)).thenReturn(entityType);
when(simpleHttpClient.get(eq("fake-path"), anyMap(), eq("tenant_01"))).thenReturn("""
when(crossTenantHttpClient.get(eq("fake-path"), anyMap(), eq("tenant_01"))).thenReturn("""
{
"what": {
"ever": {
Expand All @@ -372,7 +376,7 @@ void shouldReturnValuesFromApi() {
}
}
""");
when(simpleHttpClient.get(eq("fake-path"), anyMap(), eq("tenant_02"))).thenThrow(FeignException.Unauthorized.class);
when(crossTenantHttpClient.get(eq("fake-path"), anyMap(), eq("tenant_02"))).thenThrow(FeignException.Unauthorized.class);

ColumnValues actualColumnValueLabel = entityTypeService.getFieldValues(entityTypeId, valueColumnName, "r");

Expand Down Expand Up @@ -440,8 +444,9 @@ void shouldReturnLanguagesFromApi() {

@Test
void shouldReturnLocalizedLanguagesFromApi() {
String tenantId = "tenant_01";
UUID entityTypeId = UUID.randomUUID();
List<String> tenantList = List.of("tenant_01");
List<String> tenantList = List.of(tenantId);
String valueColumnName = "languages";
EntityType entityType = new EntityType()
.id(entityTypeId.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ class UserTenantServiceTest {
private UserTenantService userTenantService;
@Test
void shouldGetUserTenantsResponse() {
String tenantId = "tenant_01";
String expectedResponse = "{\"totalRecords\": 1}";
when(userTenantsClient.get(eq("user-tenants"), anyMap())).thenReturn(expectedResponse);
String actualResponse = userTenantService.getUserTenantsResponse("tenant_01");
String actualResponse = userTenantService.getUserTenantsResponse(tenantId);
assertEquals(expectedResponse, actualResponse);
}
}

0 comments on commit 630ba3a

Please sign in to comment.