Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
khandramai committed Nov 15, 2024
2 parents 2aac07c + d072217 commit 83661d9
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 102 deletions.
13 changes: 12 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
## v2.1.0 - Released
## v2.1.1 - Released 2024/11/08

This release contains bugfixes.

### Bugs
* [MODEXPW-396](https://folio-org.atlassian.net/browse/MODEXPW-396) Allow additional item status updates (changes on bulk-operation)
* [MODBULKOPS-393](https://folio-org.atlassian.net/browse/MODBULKOPS-393) Issues related to display errors from DI on Confirmation screen of bulk edit MARC fields
* [MODBULKOPS-348](https://folio-org.atlassian.net/browse/MODBULKOPS-348) For bulk edit of MARC fields “Are you sure“ preview is populated based on .mrc file
* [MODBULKOPS-340](https://folio-org.atlassian.net/browse/MODBULKOPS-340) "Something went wrong" error when click "Confirm changes" button while bulk edit of MARC fields


## v2.1.0 - Released 2024/11/01

### Technical tasks
* [MODBULKOPS-384](https://folio-org.atlassian.net/browse/MODBULKOPS-384) Support Eureka permissions model for bulk operations (write operations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import static org.folio.bulkops.domain.dto.UpdateOptionType.ELECTRONIC_ACCESS_URL_RELATIONSHIP;
import static org.folio.bulkops.domain.dto.UpdateOptionType.PERMANENT_LOCATION;
import static org.folio.bulkops.domain.dto.UpdateOptionType.SUPPRESS_FROM_DISCOVERY;
import static org.folio.bulkops.domain.dto.UpdateActionType.FIND_AND_REPLACE;
import static org.folio.bulkops.domain.dto.UpdateActionType.FIND_AND_REMOVE_THESE;
import static org.folio.bulkops.domain.dto.UpdateOptionType.TEMPORARY_LOCATION;
import static org.folio.bulkops.util.Constants.ARRAY_DELIMITER;
import static org.folio.bulkops.util.Constants.MARC;
Expand All @@ -39,6 +41,7 @@
import org.folio.bulkops.exception.NotFoundException;
import org.folio.bulkops.exception.RuleValidationException;
import org.folio.bulkops.exception.RuleValidationTenantsException;
import org.folio.bulkops.service.ConsortiaService;
import org.folio.bulkops.service.HoldingsReferenceService;
import org.folio.bulkops.service.ItemReferenceService;
import org.folio.bulkops.service.ElectronicAccessReferenceService;
Expand All @@ -60,6 +63,7 @@ public class HoldingsDataProcessor extends AbstractDataProcessor<ExtendedHolding
private final HoldingsNotesUpdater holdingsNotesUpdater;
private final ElectronicAccessUpdaterFactory electronicAccessUpdaterFactory;
private final ElectronicAccessReferenceService electronicAccessReferenceService;
private final ConsortiaService consortiaService;

private static final Pattern UUID_REGEX =
Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
Expand Down Expand Up @@ -211,10 +215,10 @@ private boolean ruleTenantsAreNotValid(BulkOperationRule rule, Action action, Up
if (isThereIntersectionBetween(ruleTenants, actionTenants)) {
return !ruleTenants.contains(extendedHolding.getTenant());
}
if (nonNull(ruleTenants) && nonNull(actionTenants) && ruleTenants.isEmpty() && actionTenants.isEmpty() &&
option == ELECTRONIC_ACCESS_URL_RELATIONSHIP && action.getType() == UpdateActionType.FIND_AND_REPLACE) {
if (areTenantsNotOverlapping(action, option, ruleTenants, actionTenants)) {
log.info("extendedHolding: {}, action: {}", extendedHolding, action);
return isNull(extendedHolding.getElectronicAccess()) ||
extendedHolding.getElectronicAccess().stream().noneMatch(el -> el.getRelationshipId().equals(action.getUpdated()));
extendedHolding.getElectronicAccess().stream().noneMatch(el -> Objects.equals(el.getRelationshipId(), action.getUpdated()));
}
return nonNull(ruleTenants) && !ruleTenants.isEmpty() && !ruleTenants.contains(extendedHolding.getTenant()) ||
nonNull(actionTenants) && !actionTenants.isEmpty() && !actionTenants.contains(extendedHolding.getTenant());
Expand All @@ -227,4 +231,10 @@ private boolean isThereIntersectionBetween(List<String> ruleTenants, List<String
}
return false;
}

private boolean areTenantsNotOverlapping(Action action, UpdateOptionType option, List<String> ruleTenants, List<String> actionTenants) {
return consortiaService.isTenantInConsortia(folioExecutionContext.getTenantId()) &&
nonNull(ruleTenants) && nonNull(actionTenants) && ruleTenants.isEmpty() && actionTenants.isEmpty() &&
option == ELECTRONIC_ACCESS_URL_RELATIONSHIP && (action.getType() == FIND_AND_REPLACE || action.getType() == FIND_AND_REMOVE_THESE);
}
}
11 changes: 4 additions & 7 deletions src/main/java/org/folio/bulkops/processor/ItemDataProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import static org.folio.bulkops.domain.dto.UpdateActionType.REPLACE_WITH;
import static org.folio.bulkops.domain.dto.UpdateActionType.SET_TO_FALSE;
import static org.folio.bulkops.domain.dto.UpdateActionType.SET_TO_TRUE;
import static org.folio.bulkops.domain.dto.UpdateOptionType.ELECTRONIC_ACCESS_URL_RELATIONSHIP;
import static org.folio.bulkops.domain.dto.UpdateOptionType.PERMANENT_LOAN_TYPE;
import static org.folio.bulkops.domain.dto.UpdateOptionType.STATUS;
import static org.folio.bulkops.domain.dto.UpdateOptionType.SUPPRESS_FROM_DISCOVERY;
Expand All @@ -30,6 +29,7 @@
import org.folio.bulkops.exception.BulkOperationException;
import org.folio.bulkops.exception.RuleValidationException;
import org.folio.bulkops.exception.RuleValidationTenantsException;
import org.folio.bulkops.service.ConsortiaService;
import org.folio.bulkops.service.HoldingsReferenceService;
import org.folio.bulkops.service.ItemReferenceService;
import org.folio.bulkops.util.RuleUtils;
Expand All @@ -46,6 +46,7 @@ public class ItemDataProcessor extends AbstractDataProcessor<ExtendedItem> {
private final HoldingsReferenceService holdingsReferenceService;
private final ItemReferenceService itemReferenceService;
private final ItemsNotesUpdater itemsNotesUpdater;
private final ConsortiaService consortiaService;

@Override
public Validator<UpdateOptionType, Action, BulkOperationRule> validator(ExtendedItem extendedItem) {
Expand All @@ -68,7 +69,7 @@ public Validator<UpdateOptionType, Action, BulkOperationRule> validator(Extended
throw new RuleValidationException(
format("New status value \"%s\" is not allowed", action.getUpdated()));
}
if (nonNull(rule) && ruleTenantsAreNotValid(rule, action, option, extendedItem)) {
if (nonNull(rule) && ruleTenantsAreNotValid(rule, action, extendedItem)) {
throw new RuleValidationTenantsException(String.format(RECORD_CANNOT_BE_UPDATED_ERROR_TEMPLATE,
extendedItem.getIdentifier(org.folio.bulkops.domain.dto.IdentifierType.ID), extendedItem.getTenant(), getRecordPropertyName(option)));
}
Expand Down Expand Up @@ -164,17 +165,13 @@ private ItemLocation getEffectiveLocation(Item item, String tenantId) {
}
}

private boolean ruleTenantsAreNotValid(BulkOperationRule rule, Action action, UpdateOptionType option, ExtendedItem extendedItem) {
private boolean ruleTenantsAreNotValid(BulkOperationRule rule, Action action, ExtendedItem extendedItem) {
var ruleTenants = rule.getRuleDetails().getTenants();
var actionTenants = action.getTenants();
if (nonNull(ruleTenants) && !ruleTenants.isEmpty() && nonNull(actionTenants) && !actionTenants.isEmpty()) {
ruleTenants.retainAll(actionTenants);
return !ruleTenants.contains(extendedItem.getTenant());
}
if (nonNull(ruleTenants) && nonNull(actionTenants) && ruleTenants.isEmpty() && actionTenants.isEmpty() &&
option == ELECTRONIC_ACCESS_URL_RELATIONSHIP && action.getType() == org.folio.bulkops.domain.dto.UpdateActionType.FIND_AND_REPLACE) {
return true;
}
return nonNull(ruleTenants) && !ruleTenants.isEmpty() && !ruleTenants.contains(extendedItem.getTenant()) ||
nonNull(actionTenants) && !actionTenants.isEmpty() && !actionTenants.contains(extendedItem.getTenant());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.folio.bulkops.domain.entity.BulkOperation;
import org.folio.bulkops.service.ConsortiaService;
import org.folio.bulkops.service.NoteTableUpdater;
import org.folio.bulkops.util.CSVHelper;
import org.folio.spring.FolioExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
Expand Down Expand Up @@ -69,7 +70,7 @@ public byte[] processCsvContent(byte[] input, BulkOperation bulkOperation) {
.toList();

try (var reader = new CSVReaderBuilder(new InputStreamReader(new ByteArrayInputStream(input)))
.withCSVParser(new RFC4180ParserBuilder().build()).build();
.withCSVParser(CSVHelper.getCsvParser()).build();
var stringWriter = new StringWriter()) {
String[] line;
while ((line = reader.readNext()) != null) {
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/org/folio/bulkops/service/ErrorService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static org.folio.bulkops.domain.dto.OperationStatusType.DATA_MODIFICATION;
import static org.folio.bulkops.domain.dto.OperationStatusType.REVIEWED_NO_MARC_RECORDS;
import static org.folio.bulkops.domain.dto.OperationStatusType.REVIEW_CHANGES;
import static org.folio.bulkops.util.Constants.DATA_IMPORT_ERROR_DISCARDED;
import static org.folio.bulkops.util.Constants.MSG_NO_CHANGE_REQUIRED;

import java.io.ByteArrayInputStream;
Expand All @@ -25,6 +26,7 @@
import org.folio.bulkops.client.BulkEditClient;
import org.folio.bulkops.client.MetadataProviderClient;
import org.folio.bulkops.client.RemoteFileSystemClient;
import org.folio.bulkops.domain.bean.JobLogEntry;
import org.folio.bulkops.domain.bean.StateType;
import org.folio.bulkops.domain.dto.Error;
import org.folio.bulkops.domain.dto.Errors;
Expand Down Expand Up @@ -109,7 +111,7 @@ public void saveErrorsFromDataImport(UUID bulkOperationId, UUID dataImportJobId)
try {
var jobLogEntries = metadataProviderClient.getJobLogEntries(dataImportJobId.toString(), Integer.MAX_VALUE)
.getEntries().stream()
.filter(entry -> nonNull(entry.getError()) && !entry.getError().isEmpty())
.filter(entry -> nonNull(entry.getError()))
.toList();
jobLogEntries.forEach(errorEntry -> {
List<String> identifierList = null;
Expand All @@ -120,6 +122,9 @@ public void saveErrorsFromDataImport(UUID bulkOperationId, UUID dataImportJobId)
identifierList = relatedInstanceInfo.getHridList();
}
var identifier = CollectionUtils.isEmpty(identifierList) ? null : identifierList.get(0);
if (errorEntry.getSourceRecordActionStatus() == JobLogEntry.ActionStatus.DISCARDED && errorEntry.getError().isEmpty()) {
errorEntry.setError(DATA_IMPORT_ERROR_DISCARDED);
}
saveError(bulkOperationId, identifier, errorEntry.getError());
});
} catch (Exception e) {
Expand Down
8 changes: 3 additions & 5 deletions src/main/java/org/folio/bulkops/util/CSVHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@

import com.opencsv.CSVParser;
import com.opencsv.CSVParserBuilder;
import lombok.Getter;
import lombok.experimental.UtilityClass;

@UtilityClass
public class CSVHelper {
private static final char ASCII_ZERO_CHAR = '\0';
private static CSVParser csvParser;
@Getter
private static final CSVParser csvParser;

static {
csvParser = new CSVParserBuilder().withEscapeChar(ASCII_ZERO_CHAR).build();
}

public static CSVParser getCsvParser() {
return csvParser;
}
}
1 change: 1 addition & 0 deletions src/main/java/org/folio/bulkops/util/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class Constants {

public static final String CSV_MSG_ERROR_TEMPLATE_OPTIMISTIC_LOCKING = "The record cannot be saved because it is not the most recent version. Stored version is %s, bulk edit version is %s.";
public static final String RECORD_CANNOT_BE_UPDATED_ERROR_TEMPLATE = "%s cannot be updated because the record is associated with %s and %s is not associated with this tenant.";
public static final String DATA_IMPORT_ERROR_DISCARDED = "An error occurred during the update operation, possibly due to multiple MARC records linked to the same instance. Please review the inventory for potential data inconsistencies.";
public static final String ITEM_TYPE = "ITEM";
public static final String HOLDING_TYPE = "HOLDINGS_RECORD";
public static final Set<String> SPLIT_NOTE_ENTITIES = Set.of(ITEM_TYPE, HOLDING_TYPE);
Expand Down
Loading

0 comments on commit 83661d9

Please sign in to comment.