From 2c4be97272c81be2791283b68a373dc25d3ceb2e Mon Sep 17 00:00:00 2001 From: Javokhir Abdullaev <101543142+JavokhirAbdullayev@users.noreply.github.com> Date: Tue, 15 Oct 2024 20:03:58 +0500 Subject: [PATCH] MODSOURMAN-1232 Add the option to exclude job profile names to GET "/metadata-provider/jobExecutions" endpoint (#937) * MODSOURMAN-1232 Add the option to exclude job profile names to GET "/metadata-provider/jobExecutions" endpoint * add test * fix pr comment * fix test * small fixes --- NEWS.md | 1 + .../org/folio/dao/JobExecutionFilter.java | 33 +++++++++----- .../folio/rest/impl/MetadataProviderImpl.java | 10 +++-- .../MetadataProviderJobExecutionAPITest.java | 43 +++++++++++++++++++ ramls/metadata-provider.raml | 5 +++ 5 files changed, 78 insertions(+), 14 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9a1256e8e..824b4c1b7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,5 @@ ## 2024-xx-xx v3.9.0-SNAPSHOT +* [MODSOURMAN-1232](https://folio-org.atlassian.net/browse/MODSOURMAN-1232) Add the option to exclude job profile names to GET "/metadata-provider/jobExecutions" endpoint * [MODSOURMAN-1195](https://folio-org.atlassian.net/browse/MODSOURMAN-1195) Save job execution progress in batches * [MODSOURMAN-1166](https://folio-org.atlassian.net/browse/MODSOURMAN-1166) Sorting by Autority, Order and Error columns is not working on Log details page * [MODDATAIMP-1029](https://folio-org.atlassian.net/browse/MODDATAIMP-1029) The authority record loaded via data-import using Default - Create SRS MARC Authority job profile is duplicated on the job-summary page diff --git a/mod-source-record-manager-server/src/main/java/org/folio/dao/JobExecutionFilter.java b/mod-source-record-manager-server/src/main/java/org/folio/dao/JobExecutionFilter.java index 33e4ca8be..ceea9121c 100644 --- a/mod-source-record-manager-server/src/main/java/org/folio/dao/JobExecutionFilter.java +++ b/mod-source-record-manager-server/src/main/java/org/folio/dao/JobExecutionFilter.java @@ -9,6 +9,7 @@ import java.util.stream.Collectors; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; +import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.folio.dao.util.JobExecutionDBConstants.COMPLETED_DATE_FIELD; import static org.folio.dao.util.JobExecutionDBConstants.FILE_NAME_FIELD; @@ -16,6 +17,7 @@ import static org.folio.dao.util.JobExecutionDBConstants.IS_DELETED_FIELD; import static org.folio.dao.util.JobExecutionDBConstants.JOB_PROFILE_HIDDEN_FIELD; import static org.folio.dao.util.JobExecutionDBConstants.JOB_PROFILE_ID_FIELD; +import static org.folio.dao.util.JobExecutionDBConstants.JOB_PROFILE_NAME_FIELD; import static org.folio.dao.util.JobExecutionDBConstants.STATUS_FIELD; import static org.folio.dao.util.JobExecutionDBConstants.SUBORDINATION_TYPE_FIELD; import static org.folio.dao.util.JobExecutionDBConstants.UI_STATUS_FIELD; @@ -24,6 +26,7 @@ public class JobExecutionFilter { public static final String LIKE = "LIKE"; public static final String ILIKE = "ILIKE"; + private static final String NOT = "NOT"; private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); private List statusAny; private List profileIdNotAny; @@ -37,6 +40,7 @@ public class JobExecutionFilter { private String userId; private Date completedAfter; private Date completedBefore; + private String excludeJobProfileName; public JobExecutionFilter withStatusAny(List statusAny) { this.statusAny = statusAny; @@ -68,6 +72,11 @@ public JobExecutionFilter withFileNamePattern(String fileNamePattern) { return this; } + public JobExecutionFilter withExcludeJobProfileName(String excludeJobProfileName) { + this.excludeJobProfileName = excludeJobProfileName; + return this; + } + public JobExecutionFilter withFileNameNotAny(List fileNameNotAny) { this.fileNameNotAny = fileNameNotAny; return this; @@ -121,16 +130,19 @@ public String buildCriteria() { addCondition(conditionBuilder, buildInCondition(UI_STATUS_FIELD, uiStatuses)); } if (isNotEmpty(hrIdPattern) && isNotEmpty(fileNamePattern)) { - conditionBuilder.append(String.format(" AND (%s OR %s)", buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern), - buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern))); + conditionBuilder.append(String.format(" AND (%s OR %s)", buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern, false), + buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern, false))); } else { if (isNotEmpty(hrIdPattern)) { - addCondition(conditionBuilder, buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern)); + addCondition(conditionBuilder, buildCaseSensitiveLikeCondition(HRID_FIELD, hrIdPattern, false)); } if (isNotEmpty(fileNamePattern)) { - addCondition(conditionBuilder, buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern)); + addCondition(conditionBuilder, buildCaseInsensitiveLikeCondition(FILE_NAME_FIELD, fileNamePattern, false)); } } + if (isNotEmpty(excludeJobProfileName)) { + addCondition(conditionBuilder, buildCaseInsensitiveLikeCondition(JOB_PROFILE_NAME_FIELD, excludeJobProfileName, true)); + } if (isNotEmpty(fileNameNotAny)) { addCondition(conditionBuilder, buildNotInCondition(FILE_NAME_FIELD, fileNameNotAny)); } @@ -195,18 +207,19 @@ private String buildLessThanOrEqualCondition(String columnName, String value) { return String.format("%s <= '%s'", columnName, value); } - private String buildCaseSensitiveLikeCondition(String columnName, String pattern) { - return buildLikeCondition(columnName, pattern, true); + private String buildCaseSensitiveLikeCondition(String columnName, String pattern, boolean denial) { + return buildLikeCondition(columnName, pattern, true, denial); } - private String buildCaseInsensitiveLikeCondition(String columnName, String pattern) { - return buildLikeCondition(columnName, pattern, false); + private String buildCaseInsensitiveLikeCondition(String columnName, String pattern, boolean denial) { + return buildLikeCondition(columnName, pattern, false, denial); } - private String buildLikeCondition(String columnName, String pattern, boolean isCaseSensitive) { + private String buildLikeCondition(String columnName, String pattern, boolean isCaseSensitive, boolean denial) { String preparedLikePattern = pattern.replace("*", "%"); String likeOperator = isCaseSensitive ? LIKE : ILIKE; - return String.format("%s::text %s '%s'", columnName, likeOperator, preparedLikePattern); + String denyOperator = denial ? NOT : EMPTY; + return String.format("%s::text %s %s '%s'", columnName, denyOperator, likeOperator, preparedLikePattern); } } diff --git a/mod-source-record-manager-server/src/main/java/org/folio/rest/impl/MetadataProviderImpl.java b/mod-source-record-manager-server/src/main/java/org/folio/rest/impl/MetadataProviderImpl.java index edcc865a1..f4aa0f01c 100644 --- a/mod-source-record-manager-server/src/main/java/org/folio/rest/impl/MetadataProviderImpl.java +++ b/mod-source-record-manager-server/src/main/java/org/folio/rest/impl/MetadataProviderImpl.java @@ -62,8 +62,8 @@ public MetadataProviderImpl(Vertx vertx, String tenantId) { //NOSONAR } @Override - public void getMetadataProviderJobExecutions(List statusAny, List profileIdNotAny, String statusNot, - List uiStatusAny, String hrId, String fileName, List fileNameNotAny, + public void getMetadataProviderJobExecutions(String excludeJobProfileName, List statusAny, List profileIdNotAny, + String statusNot, List uiStatusAny, String hrId, String fileName, List fileNameNotAny, List profileIdAny, List subordinationTypeNotAny, String userId, Date completedAfter, Date completedBefore, List sortBy, String totalRecords, int offset, int limit, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { @@ -72,7 +72,7 @@ public void getMetadataProviderJobExecutions(List statusAny, List sortFields = mapSortQueryToSortFields(sortBy); JobExecutionFilter filter = buildJobExecutionFilter(statusAny, profileIdNotAny, statusNot, uiStatusAny, hrId, fileName, fileNameNotAny, profileIdAny, - subordinationTypeNotAny, userId, completedAfter, completedBefore); + subordinationTypeNotAny, userId, completedAfter, completedBefore, excludeJobProfileName); jobExecutionService.getJobExecutionsWithoutParentMultiple(filter, sortFields, offset, limit, tenantId) .map(GetMetadataProviderJobExecutionsResponse::respond200WithApplicationJson) .map(Response.class::cast) @@ -223,7 +223,8 @@ public void getMetadataProviderIncomingRecordsByRecordId(String recordId, Map statusAny, List profileIdNotAny, String statusNot, List uiStatusAny, String hrIdPattern, String fileNamePattern, List fileNameNotAny, List profileIdAny, List subordinationTypeNotAny, - String userId, Date completedAfter, Date completedBefore) { + String userId, Date completedAfter, Date completedBefore, + String excludeJobProfileName) { List statuses = statusAny.stream() .map(JobExecution.Status::fromValue) .toList(); @@ -239,6 +240,7 @@ private JobExecutionFilter buildJobExecutionFilter(List statusAny, List< return new JobExecutionFilter() .withStatusAny(statuses) .withProfileIdNotAny(profileIdNotAny) + .withExcludeJobProfileName(excludeJobProfileName) .withStatusNot(statusNot == null ? null : JobExecution.Status.fromValue(statusNot)) .withUiStatusAny(uiStatuses) .withHrIdPattern(hrIdPattern) diff --git a/mod-source-record-manager-server/src/test/java/org/folio/rest/impl/metadataProvider/MetadataProviderJobExecutionAPITest.java b/mod-source-record-manager-server/src/test/java/org/folio/rest/impl/metadataProvider/MetadataProviderJobExecutionAPITest.java index b50b6fb45..8e335a6d7 100644 --- a/mod-source-record-manager-server/src/test/java/org/folio/rest/impl/metadataProvider/MetadataProviderJobExecutionAPITest.java +++ b/mod-source-record-manager-server/src/test/java/org/folio/rest/impl/metadataProvider/MetadataProviderJobExecutionAPITest.java @@ -547,6 +547,49 @@ public void shouldReturnFilteredCollectionByHrIdOnGet() { .body("jobExecutions[0].hrId", is(expectedHrid)); } + @Test + public void shouldReturnFilteredCollectionByExcludeJobProfileNameOnGet() { + List createdJobExecution = constructAndPostInitJobExecutionRqDto(4).getJobExecutions(); + List childJobsToUpdate = createdJobExecution.stream() + .filter(jobExecution -> jobExecution.getSubordinationType().equals(CHILD)) + .collect(Collectors.toList()); + + List profilesNames = List.of("air", "Apple", "driver", "Zero"); + + for (int i = 0; i < childJobsToUpdate.size(); i++) { + childJobsToUpdate.get(i).withJobProfileInfo(new JobProfileInfo() + .withId(UUID.randomUUID().toString()) + .withName(profilesNames.get(i)) + .withDataType(MARC)); + putJobExecution(childJobsToUpdate.get(i)); + } + + RestAssured.given() + .spec(spec) + .when() + .queryParam("excludeJobProfileName", "air") + .get(GET_JOB_EXECUTIONS_PATH) + .then() + .statusCode(HttpStatus.SC_OK) + .body("jobExecutions.size()", is(3)) + .body("totalRecords", is(3)); + } + + @Test + public void shouldReturnFilteredCollectionByExcludeJobProfileNameWithWildcardOnGet() { + constructAndPostInitJobExecutionRqDto(5); + + RestAssured.given() + .spec(spec) + .when() + .queryParam("excludeJobProfileName", "importBib*") + .get(GET_JOB_EXECUTIONS_PATH) + .then() + .statusCode(HttpStatus.SC_OK) + .body("jobExecutions.size()", is(0)) + .body("totalRecords", is(0)); + } + @Test public void shouldReturnFilteredCollectionByFileNameOnGet() { constructAndPostInitJobExecutionRqDto(5); diff --git a/ramls/metadata-provider.raml b/ramls/metadata-provider.raml index 2088a9fe3..276b65818 100644 --- a/ramls/metadata-provider.raml +++ b/ramls/metadata-provider.raml @@ -40,6 +40,11 @@ resourceTypes: pageable ] queryParameters: + excludeJobProfileName: + description: Filter by Job profiles name + type: string + example: Bulk operations data import job profile - * + required: false statusAny: description: JobExecution statuses to filter by type: string[]