diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index ff9174305..a939e9d38 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -146,7 +146,7 @@ "provides": [ { "id": "bulk-edit", - "version": "3.0", + "version": "4.0", "handlers": [ { "methods": [ "POST" ], @@ -210,75 +210,6 @@ "consortium-search.items.collection.get" ] }, - { - "methods": [ "POST" ], - "pathPattern": "/bulk-edit/{id}/item-content-update/upload", - "permissionsRequired": [ "bulk-edit.items-content-update.collection.post" ], - "modulePermissions": [ - "inventory-storage.call-number-types.item.get", - "inventory-storage.call-number-types.collection.get", - "inventory-storage.item-damaged-statuses.item.get", - "inventory-storage.item-damaged-statuses.collection.get", - "inventory-storage.electronic-access-relationships.item.get", - "inventory-storage.electronic-access-relationships.collection.get", - "inventory-storage.item-note-types.item.get", - "inventory-storage.item-note-types.collection.get", - "inventory-storage.service-points.item.get", - "inventory-storage.service-points.collection.get", - "inventory-storage.statistical-codes.item.get", - "inventory-storage.statistical-codes.collection.get", - "inventory-storage.material-types.item.get", - "inventory-storage.material-types.collection.get", - "inventory-storage.loan-types.item.get", - "inventory-storage.loan-types.collection.get", - "inventory-storage.locations.item.get", - "inventory-storage.locations.collection.get", - "inventory-storage.instances.item.get", - "inventory-storage.instances.collection.get", - "inventory-storage.holdings.item.get", - "inventory-storage.holdings.collection.get", - "configuration.entries.collection.get" - ] - }, - { - "methods": [ "POST" ], - "pathPattern": "/bulk-edit/{id}/user-content-update/upload", - "permissionsRequired": [ "bulk-edit.users-content-update.collection.post" ], - "modulePermissions": [ - "users.collection.get", - "users.item.get", - "users.item.put", - "usergroups.item.get", - "addresstypes.item.get", - "proxiesfor.item.get", - "departments.item.get", - "usergroups.collection.get", - "addresstypes.collection.get" - ] - }, - { - "methods": [ "POST" ], - "pathPattern": "/bulk-edit/{id}/holdings-content-update/upload", - "permissionsRequired": [ "bulk-edit.holdings-content-update.collection.post" ], - "modulePermissions": [ - "inventory-storage.instances.item.get", - "inventory-storage.holdings-types.collection.get", - "inventory-storage.holdings-types.item.get", - "inventory-storage.locations.collection.get", - "inventory-storage.locations.item.get", - "inventory-storage.call-number-types.collection.get", - "inventory-storage.call-number-types.item.get", - "inventory-storage.holdings-note-types.collection.get", - "inventory-storage.holdings-note-types.item.get", - "inventory-storage.ill-policies.collection.get", - "inventory-storage.ill-policies.item.get", - "inventory-storage.holdings-sources.collection.get", - "inventory-storage.holdings-sources.item.get", - "inventory-storage.statistical-codes.collection.get", - "inventory-storage.statistical-codes.item.get", - "inventory-storage.electronic-access-relationships.collection.get" - ] - }, { "methods": [ "POST" ], "pathPattern": "/bulk-edit/{id}/start", @@ -331,104 +262,6 @@ "inventory-storage.holdings.item.put" ] }, - { - "methods": [ - "POST" - ], - "pathPattern": "/bulk-edit/{jobId}/roll-back", - "permissionsRequired": [ - "bulk-edit.roll-back.item.post" - ], - "modulePermissions": [ - "users.collection.get", - "users.item.get", - "users.item.put", - "usergroups.item.get", - "addresstypes.item.get", - "proxiesfor.item.get", - "departments.item.get", - "usergroups.collection.get", - "addresstypes.collection.get", - "data-export.job.item.get" - ] - }, - { - "methods": [ "GET" ], - "pathPattern": "/bulk-edit/{jobId}/preview/users", - "permissionsRequired": [ "bulk-edit.preview-users.collection.get" ], - "modulePermissions": [ - "users.collection.get", - "addresstypes.collection.get", - "usergroups.collection.get" - ] - }, - { - "methods": [ "GET" ], - "pathPattern": "/bulk-edit/{jobId}/preview/items", - "permissionsRequired": [ "bulk-edit.preview-items.collection.get" ], - "modulePermissions": [ - "inventory.items.collection.get", - "inventory-storage.material-types.collection.get", - "inventory-storage.statistical-codes.collection.get", - "inventory-storage.item-note-types.collection.get", - "inventory-storage.call-number-types.collection.get", - "inventory-storage.electronic-access-relationships.collection.get", - "inventory-storage.service-points.collection.get", - "users.collection.get", - "inventory-storage.locations.collection.get", - "inventory-storage.loan-types.collection.get", - "inventory-storage.item-damaged-statuses.collection.get", - "inventory-storage.instances.collection.get", - "inventory-storage.holdings.collection.get", - "configuration.entries.collection.get" - ] - }, - { - "methods": [ "GET" ], - "pathPattern": "/bulk-edit/{jobId}/preview/holdings", - "permissionsRequired": [ "bulk-edit.preview-holdings.collection.get" ], - "modulePermissions": [ - "inventory-storage.holdings.collection.get", - "inventory-storage.holdings-types.collection.get", - "inventory-storage.holdings-types.item.get", - "inventory-storage.locations.collection.get", - "inventory-storage.locations.item.get", - "inventory-storage.call-number-types.collection.get", - "inventory-storage.call-number-types.item.get", - "inventory-storage.ill-policies.collection.get", - "inventory-storage.ill-policies.item.get", - "inventory-storage.holdings-sources.collection.get", - "inventory-storage.instances.item.get", - "inventory-storage.statistical-codes.collection.get", - "inventory-storage.statistical-codes.item.get", - "inventory-storage.electronic-access-relationships.collection.get", - "inventory-storage.holdings-note-types.collection.get" - ] - }, - { - "methods": [ "GET" ], - "pathPattern": "/bulk-edit/{jobId}/errors", - "permissionsRequired": [ "bulk-edit.errors.collection.get" ], - "modulePermissions": [] - }, - { - "methods": [ "GET" ], - "pathPattern": "/bulk-edit/{jobId}/preview/updated-items/download", - "permissionsRequired": [ "bulk-edit.preview.updated-items.collection.get" ], - "modulePermissions": [] - }, - { - "methods": [ "GET" ], - "pathPattern": "/bulk-edit/{jobId}/preview/updated-users/download", - "permissionsRequired": [ "bulk-edit.preview.updated-users.collection.get" ], - "modulePermissions": [] - }, - { - "methods": [ "GET" ], - "pathPattern": "/bulk-edit/{jobId}/preview/updated-holdings/download", - "permissionsRequired": [ "bulk-edit.preview.updated-holdings.collection.get" ], - "modulePermissions": [] - }, { "methods": [ "GET" ], "pathPattern": "/refresh-presigned-url", @@ -489,66 +322,11 @@ "displayName" : "upload identifiers list", "description" : "Upload list of item identifiers" }, - { - "permissionName" : "bulk-edit.items-content-update.collection.post", - "displayName" : "upload items content update collection", - "description" : "Upload collection of item content updates" - }, - { - "permissionName" : "bulk-edit.users-content-update.collection.post", - "displayName" : "upload users content update collection", - "description" : "Upload collection of user content updates" - }, - { - "permissionName" : "bulk-edit.holdings-content-update.collection.post", - "displayName" : "upload holdings records content update collection", - "description" : "Upload collection of holdings records content updates" - }, - { - "permissionName" : "bulk-edit.preview.updated-items.collection.get", - "displayName" : "download updated items preview csv", - "description" : "Download csv of preview updated items" - }, - { - "permissionName" : "bulk-edit.preview.updated-users.collection.get", - "displayName" : "download updated users preview csv", - "description" : "Download csv with preview of updated users" - }, - { - "permissionName" : "bulk-edit.preview.updated-holdings.collection.get", - "displayName" : "download updated holdings records preview csv", - "description" : "Download csv with preview of updated holdings records" - }, { "permissionName": "bulk-edit.start.item.post", "displayName": "start update items", "description": "Start update items" }, - { - "permissionName": "bulk-edit.roll-back.item.post", - "displayName": "roll back list of uploaded items", - "description": "Roll back list of uploaded items" - }, - { - "permissionName" : "bulk-edit.preview-users.collection.get", - "displayName" : "get N users for preview", - "description" : "Get N users for preview" - }, - { - "permissionName" : "bulk-edit.preview-items.collection.get", - "displayName" : "get N items for preview", - "description" : "Get N items for preview" - }, - { - "permissionName" : "bulk-edit.preview-holdings.collection.get", - "displayName" : "get N holdings for preview", - "description" : "Get N holdings for preview" - }, - { - "permissionName" : "bulk-edit.errors.collection.get", - "displayName" : "get errors for preview", - "description" : "Get errors for preview" - }, { "permissionName" : "refresh-presigned-url.get", "displayName" : "Get refreshed presigned url for export file", @@ -560,18 +338,7 @@ "description" : "All permissions for bulk-edit module", "subPermissions" : [ "bulk-edit.item.post", - "bulk-edit.items-content-update.collection.post", - "bulk-edit.users-content-update.collection.post", - "bulk-edit.holdings-content-update.collection.post", - "bulk-edit.preview.updated-items.collection.get", - "bulk-edit.preview.updated-users.collection.get", - "bulk-edit.preview.updated-holdings.collection.get", - "bulk-edit.start.item.post", - "bulk-edit.roll-back.item.post", - "bulk-edit.preview-users.collection.get", - "bulk-edit.preview-items.collection.get", - "bulk-edit.preview-holdings.collection.get", - "bulk-edit.errors.collection.get" + "bulk-edit.start.item.post" ] }, { diff --git a/folio-export-common b/folio-export-common index 4aae4a204..62036172d 160000 --- a/folio-export-common +++ b/folio-export-common @@ -1 +1 @@ -Subproject commit 4aae4a204d0e69a2056632ad36715d774843479a +Subproject commit 62036172dba915fd086f35c4ec35484695be0f19 diff --git a/src/main/java/org/folio/dew/batch/JobCompletionNotificationListener.java b/src/main/java/org/folio/dew/batch/JobCompletionNotificationListener.java index 8fa09fdbc..6310a4d6a 100644 --- a/src/main/java/org/folio/dew/batch/JobCompletionNotificationListener.java +++ b/src/main/java/org/folio/dew/batch/JobCompletionNotificationListener.java @@ -62,7 +62,6 @@ import org.folio.dew.error.BulkEditException; import org.folio.dew.repository.LocalFilesStorage; import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.service.BulkEditChangedRecordsService; import org.folio.dew.service.BulkEditProcessingErrorsService; import org.folio.dew.service.BulkEditStatisticService; import org.folio.dew.utils.CsvHelper; @@ -83,7 +82,6 @@ public class JobCompletionNotificationListener implements JobExecutionListener { private final LocalFilesStorage localFilesStorage; private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; private final BulkEditStatisticService bulkEditStatisticService; - private final BulkEditChangedRecordsService changedRecordsService; @Override public void beforeJob(JobExecution jobExecution) { @@ -111,15 +109,6 @@ private void processJobUpdate(JobExecution jobExecution, boolean after) { handleProcessingMatchedRecordsAndErrors(jobExecution, jobId); handleProcessingMarcFile(jobExecution); } - if (isBulkEditUpdateJob(jobExecution)) { - handleProcessingChangedRecords(jobExecution); - String downloadErrorLink = bulkEditProcessingErrorsService.saveErrorFileAndGetDownloadLink(jobId, jobExecution); - var isChangedRecordsLinkPresent = jobExecution.getExecutionContext().containsKey(OUTPUT_FILES_IN_STORAGE); - jobExecution.getExecutionContext().putString(OUTPUT_FILES_IN_STORAGE, - (isChangedRecordsLinkPresent ? jobExecution.getExecutionContext().getString(OUTPUT_FILES_IN_STORAGE) : EMPTY) + - PATHS_DELIMITER + (StringUtils.isNotBlank(downloadErrorLink) ? downloadErrorLink : EMPTY)); - - } processJobAfter(jobId, jobParameters); } else { if (jobExecution.getJobInstance().getJobName().contains(BULK_EDIT_UPDATE.getValue())) { @@ -142,7 +131,7 @@ private void processJobUpdate(JobExecution jobExecution, boolean after) { } var jobExecutionUpdate = createJobExecutionUpdate(jobId, jobExecution); - if (jobExecution.getJobInstance().getJobName().contains(BULK_EDIT_UPDATE.getValue()) || jobExecution.getJobInstance().getJobName().contains(BULK_EDIT_IDENTIFIERS.getValue())) { + if (jobExecution.getJobInstance().getJobName().contains(BULK_EDIT_IDENTIFIERS.getValue())) { var progress = new Progress(); if (jobExecution.getStatus() == BatchStatus.COMPLETED) { var fileName = FilenameUtils.getName(jobParameters.getString(FILE_NAME)); @@ -213,17 +202,13 @@ private void moveFileToStorage(String destFileName, String sourceFileName) throw private void handleProcessingMatchedRecordsAndErrors(JobExecution jobExecution, String jobId) { String downloadErrorLink = bulkEditProcessingErrorsService.saveErrorFileAndGetDownloadLink(jobId, jobExecution); - jobExecution.getExecutionContext().putString(OUTPUT_FILES_IN_STORAGE, saveResult(jobExecution, false) + PATHS_DELIMITER + (isNull(downloadErrorLink) ? EMPTY : downloadErrorLink) + PATHS_DELIMITER + saveJsonResult(jobExecution, !isBulkEditUpdateJob(jobExecution))); + jobExecution.getExecutionContext().putString(OUTPUT_FILES_IN_STORAGE, saveResult(jobExecution, false) + PATHS_DELIMITER + (isNull(downloadErrorLink) ? EMPTY : downloadErrorLink) + PATHS_DELIMITER + saveJsonResult(jobExecution, true)); } private void handleProcessingMarcFile(JobExecution jobExecution) { jobExecution.getExecutionContext().putString(OUTPUT_FILES_IN_STORAGE, jobExecution.getExecutionContext().getString(OUTPUT_FILES_IN_STORAGE) + PATHS_DELIMITER + saveMarcResult(jobExecution, false)); } - private void handleProcessingChangedRecords(JobExecution jobExecution) { - jobExecution.getExecutionContext().putString(OUTPUT_FILES_IN_STORAGE, saveResult(jobExecution, !isBulkEditUpdateJob(jobExecution))); - } - private void processJobAfter(String jobId, JobParameters jobParameters) { var tempOutputFilePath = jobParameters.getString(TEMP_OUTPUT_FILE_PATH); if (StringUtils.isBlank(tempOutputFilePath) || @@ -322,21 +307,12 @@ private boolean isBulkEditIdentifiersJob(JobExecution jobExecution) { return jobExecution.getJobInstance().getJobName().contains(BULK_EDIT_IDENTIFIERS.getValue()); } - private boolean isBulkEditUpdateJob(JobExecution jobExecution) { - return jobExecution.getJobInstance().getJobName().contains(BULK_EDIT_UPDATE.getValue()); - } - - private boolean isBulkEditContentUpdateJob(JobExecution jobExecution) { - return nonNull(jobExecution.getJobParameters().getString(UPDATED_FILE_NAME)); - } - private boolean isBulkEditQueryJob(JobExecution jobExecution) { return jobExecution.getJobInstance().getJobName().contains(BULK_EDIT_QUERY.getValue()); } private boolean isBulkEditJob(JobExecution jobExecution) { - return isBulkEditContentUpdateJob(jobExecution) || isBulkEditUpdateJob(jobExecution) || - isBulkEditIdentifiersJob(jobExecution) || isBulkEditQueryJob(jobExecution); + return isBulkEditIdentifiersJob(jobExecution) || isBulkEditQueryJob(jobExecution); } private boolean isBursarFeesFinesJob(JobExecution jobExecution) { @@ -395,13 +371,9 @@ private String saveMarcResult(JobExecution jobExecution, boolean isSourceToBeDel } private String preparePath(JobExecution jobExecution) { - if (isBulkEditContentUpdateJob(jobExecution)) { - return jobExecution.getJobParameters().getString(UPDATED_FILE_NAME); - } else if (isBulkEditUpdateJob(jobExecution)) { - return prepareChangedUsersFile(jobExecution.getJobParameters().getString(FILE_NAME), jobExecution.getJobParameters().getString(JobParameterNames.JOB_ID)); - } return jobExecution.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH); } + private boolean noRecordsFound(String path) throws Exception { if (localFilesStorage.notExists(path) && !remoteFilesStorage.containsFile(path)) { log.error("Path to found records does not exist: {}", path); @@ -419,11 +391,11 @@ private boolean noRecordsFound(String path) throws Exception { } private String prepareObject(JobExecution jobExecution, String path) { - return jobExecution.getJobParameters().getString(JobParameterNames.JOB_ID) + PATH_SEPARATOR + FilenameUtils.getName(path) + (!isBulkEditUpdateJob(jobExecution) ? CSV_EXTENSION : EMPTY); + return jobExecution.getJobParameters().getString(JobParameterNames.JOB_ID) + PATH_SEPARATOR + FilenameUtils.getName(path) + CSV_EXTENSION; } private String prepareJsonObject(JobExecution jobExecution, String path) { - return jobExecution.getJobParameters().getString(JobParameterNames.JOB_ID) + PATH_SEPARATOR + FilenameUtils.getName(path) + (!isBulkEditUpdateJob(jobExecution) ? ".json" : EMPTY); + return jobExecution.getJobParameters().getString(JobParameterNames.JOB_ID) + PATH_SEPARATOR + FilenameUtils.getName(path) + ".json"; } private String prepareMrcObject(JobExecution jobExecution, String path) { @@ -450,21 +422,4 @@ private String prepareDownloadJsonFilename(JobExecution jobExecution, String pat .replace(INITIAL_PREFIX, EMPTY); } - private String prepareChangedUsersFile(String path, String jobId) { - var updatedIds = changedRecordsService.fetchChangedUserIds(jobId); - if (isNull(updatedIds) || updatedIds.isEmpty()) { - return EMPTY; - } - try { - var updatedUserFormats = CsvHelper.readRecordsFromStorage(localFilesStorage, path, UserFormat.class, true) - .stream() - .filter(userFormat -> updatedIds.contains(userFormat.getId())) - .collect(Collectors.toList()); - CsvHelper.saveRecordsToStorage(localFilesStorage, updatedUserFormats, UserFormat.class, path); - } catch (Exception e) { - log.error("Error processing file {}: {}", path, e.getMessage()); - } - return path; - } - } diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditFilterUserRecordsForRollBackProcessor.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditFilterUserRecordsForRollBackProcessor.java deleted file mode 100644 index 3ea4fb2ee..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditFilterUserRecordsForRollBackProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.rollbackjob; - -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import org.folio.dew.domain.dto.User; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.service.BulkEditParseService; -import org.folio.dew.service.BulkEditRollBackService; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import java.util.UUID; - -@Component -@JobScope -@RequiredArgsConstructor -public class BulkEditFilterUserRecordsForRollBackProcessor implements ItemProcessor { - - @Value("#{jobParameters['jobId']}") - @Setter - private String jobId; - private final BulkEditRollBackService bulkEditRollBackService; - private final BulkEditParseService bulkEditParseService; - - @Override - public User process(UserFormat userFormat) { - if (bulkEditRollBackService.isUserBeRollBack(userFormat.getId(), UUID.fromString(jobId))) { - return bulkEditParseService.mapUserFormatToUser(userFormat); - } - return null; - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsAfterRollBackJobConfig.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsAfterRollBackJobConfig.java deleted file mode 100644 index b5ac4967c..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsAfterRollBackJobConfig.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.rollbackjob; - -import org.folio.dew.batch.bulkedit.jobs.JobConfigReaderHelper; -import org.folio.dew.domain.dto.User; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.repository.LocalFilesStorage; -import org.folio.dew.repository.S3CompatibleResource; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.configuration.annotation.StepScope; -import org.springframework.batch.core.job.builder.JobBuilder; -import org.springframework.batch.core.launch.support.RunIdIncrementer; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.StepBuilder; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemWriter; -import org.springframework.batch.item.file.FlatFileItemReader; -import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; - -@Configuration -public class BulkEditUpdateUserRecordsAfterRollBackJobConfig { - - @Bean - public Job bulkEditRollBackJob( - BulkEditUpdateUserRecordsAfterRollBackListener listener, - Step bulkEditRollBackRecordsStep, - JobRepository jobRepository) { - return new JobBuilder("BULK_EDIT_ROLL_BACK", jobRepository) - .incrementer(new RunIdIncrementer()) - .listener(listener) - .flow(bulkEditRollBackRecordsStep) - .end() - .build(); - } - - @Bean - public Step bulkEditRollBackRecordsStep( - @Qualifier("bulkEditRollBackReader") - ItemReader reader, - @Qualifier("bulkEditFilterUserRecordsForRollBackProcessor") - ItemProcessor processor, - @Qualifier("bulkEditUpdateUserRecordsForRollBackWriter") - ItemWriter writer, - JobRepository jobRepository, - PlatformTransactionManager transactionManager) { - return new StepBuilder("bulkEditRollBackRecordsStep", jobRepository) - .chunk(1, transactionManager) - .reader(reader) - .processor(processor) - .writer(writer) - .build(); - } - - @Bean - @StepScope - public FlatFileItemReader bulkEditRollBackReader(@Value("#{jobParameters['fileName']}") String fileName, LocalFilesStorage localFilesStorage) { - var userLineMapper = JobConfigReaderHelper.createLineMapper(UserFormat.class, UserFormat.getUserFieldsArray()); - return new FlatFileItemReaderBuilder() - .name("bulkEditRollBackReader") - .resource(new S3CompatibleResource<>(fileName, localFilesStorage)) - .linesToSkip(1) - .lineMapper(userLineMapper) - .build(); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsAfterRollBackListener.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsAfterRollBackListener.java deleted file mode 100644 index e7e0f7700..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsAfterRollBackListener.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.rollbackjob; - -import lombok.RequiredArgsConstructor; -import org.apache.commons.io.FileUtils; -import org.folio.dew.service.BulkEditRollBackService; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobExecutionListener; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import java.io.File; -import java.util.UUID; - -@Component -@JobScope -@RequiredArgsConstructor -public class BulkEditUpdateUserRecordsAfterRollBackListener implements JobExecutionListener { - - @Value("#{jobParameters['jobId']}") - private String jobId; - @Value("#{jobParameters['fileName']}") - private String fileName; - private final BulkEditRollBackService bulkEditRollBackService; - - @Override - public void beforeJob(JobExecution jobExecution) {} - - @Override - public void afterJob(JobExecution jobExecution) { - bulkEditRollBackService.cleanJobData(UUID.fromString(jobId)); - FileUtils.deleteQuietly(new File(fileName)); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsForRollBackWriter.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsForRollBackWriter.java deleted file mode 100644 index ed9873738..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsForRollBackWriter.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.rollbackjob; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.folio.dew.client.UserClient; -import org.folio.dew.domain.dto.User; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.Chunk; -import org.springframework.batch.item.ItemWriter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Component -@JobScope -@RequiredArgsConstructor -@Log4j2 -public class BulkEditUpdateUserRecordsForRollBackWriter implements ItemWriter { - - private final UserClient userClient; - @Value("#{jobParameters['jobId']}") - private String jobId; - - @Override - public void write(Chunk items) throws Exception { - items.forEach(user -> { - try { - userClient.updateUser(user, user.getId()); - log.info("Rollback user with id - {} from updating by job {}", user.getId(), jobId); - } catch (Exception e) { - log.info("Cannot rollback user with id {}. Reason: {}", user.getId(), e.getMessage()); - } - }); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsJobConfig.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsJobConfig.java deleted file mode 100644 index 50df4463e..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsJobConfig.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import org.folio.dew.batch.JobCompletionNotificationListener; -import org.folio.dew.batch.bulkedit.jobs.JobConfigReaderHelper; -import org.folio.dew.domain.dto.HoldingsFormat; -import org.folio.dew.domain.dto.HoldingsRecord; -import org.folio.dew.repository.RemoteFilesStorage; -import org.springframework.batch.core.ItemWriteListener; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.configuration.annotation.StepScope; -import org.springframework.batch.core.job.builder.JobBuilder; -import org.springframework.batch.core.launch.support.RunIdIncrementer; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.StepBuilder; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemWriter; -import org.springframework.batch.item.file.FlatFileItemReader; -import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.InputStreamResource; -import org.springframework.transaction.PlatformTransactionManager; - -import java.io.IOException; - -import static org.folio.dew.domain.dto.EntityType.HOLDINGS_RECORD; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.Constants.JOB_NAME_POSTFIX_SEPARATOR; - -@Configuration public class BulkEditUpdateHoldingsRecordsJobConfig { - - @Bean public Job bulkEditUpdateHoldingsRecordsJob(Step bulkEditUpdateHoldingsRecordsStep, JobRepository jobRepository, - JobCompletionNotificationListener completionListener) { - return new JobBuilder(BULK_EDIT_UPDATE.getValue() + JOB_NAME_POSTFIX_SEPARATOR + HOLDINGS_RECORD.getValue(), jobRepository) - .incrementer(new RunIdIncrementer()) - .listener(completionListener) - .flow(bulkEditUpdateHoldingsRecordsStep) - .end() - .build(); - } - - @Bean public Step bulkEditUpdateHoldingsRecordsStep(ItemReader csvHoldingsRecordsReader, - @Qualifier("bulkEditUpdateHoldingsRecordsProcessor") ItemProcessor processor, - @Qualifier("updateHoldingsRecordsWriter") ItemWriter writer, - @Qualifier("updateRecordWriteListener") ItemWriteListener updateRecordWriteListener, - JobRepository jobRepository, PlatformTransactionManager transactionManager) { - return new StepBuilder("bulkEditUpdateHoldingsRecordsStep", jobRepository) - .chunk(10, transactionManager) - .reader(csvHoldingsRecordsReader) - .processor(processor) - .writer(writer) - .listener(updateRecordWriteListener) - .build(); - } - - @Bean - @StepScope - public FlatFileItemReader csvHoldingsRecordsReader( - @Value("#{jobParameters['" + UPDATED_FILE_NAME + "']}") String updatedFileName, - RemoteFilesStorage remoteFilesStorage) - throws IOException { - var holdingsLineMapper = JobConfigReaderHelper.createLineMapper(HoldingsFormat.class, HoldingsFormat.getHoldingsFieldsArray()); - return new FlatFileItemReaderBuilder().name("holdingsReader") - .resource(new InputStreamResource(remoteFilesStorage.newInputStream(updatedFileName))) - .linesToSkip(1) - .lineMapper(holdingsLineMapper) - .build(); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsProcessor.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsProcessor.java deleted file mode 100644 index 62ff51a57..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsProcessor.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import static org.folio.dew.utils.Constants.FILE_NAME; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.dew.domain.dto.HoldingsFormat; -import org.folio.dew.domain.dto.HoldingsRecord; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.mapper.HoldingsMapper; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Log4j2 -@Component -@Qualifier("updateHoldingsRecordsProcessor") -@RequiredArgsConstructor -@JobScope -public class BulkEditUpdateHoldingsRecordsProcessor implements ItemProcessor { - - @Value("#{jobParameters['jobId']}") - private String jobId; - - @Value("#{jobParameters['identifierType']}") - private String identifierType; - - @Value("#{jobExecution}") - private JobExecution jobExecution; - - private final HoldingsMapper holdingsMapper; - private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - - @Override - public HoldingsRecord process(HoldingsFormat holdingsFormat) throws Exception { - try { - return holdingsMapper.mapToHoldingsRecord(holdingsFormat); - } catch (Exception e) { - log.error("Error process holdings format {} : {}", holdingsFormat.getIdentifier(identifierType), e.getMessage()); - bulkEditProcessingErrorsService.saveErrorInCSV(jobId, holdingsFormat.getIdentifier(identifierType), new BulkEditException(e.getMessage()), FilenameUtils.getName(jobExecution.getJobParameters().getString(FILE_NAME))); - return null; - } - } - -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsWriter.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsWriter.java deleted file mode 100644 index 7d060c0d5..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateHoldingsRecordsWriter.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.dew.client.HoldingClient; -import org.folio.dew.domain.dto.HoldingsRecord; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.BulkEditStatisticService; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.Chunk; -import org.springframework.batch.item.ItemWriter; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import static org.folio.dew.utils.Constants.FILE_NAME; - -@Log4j2 -@Component -@Qualifier("updateHoldingsRecordsWriter") -@RequiredArgsConstructor -@JobScope -public class BulkEditUpdateHoldingsRecordsWriter implements ItemWriter { - - @Value("#{jobParameters['jobId']}") - private String jobId; - @Value("#{jobExecution}") - private JobExecution jobExecution; - - private final HoldingClient holdingClient; - private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - private final BulkEditStatisticService bulkEditStatisticService; - - @Override - public void write(Chunk holdingsRecords) throws Exception { - holdingsRecords.forEach(holdingsRecord -> { - try { - holdingClient.updateHoldingsRecord(holdingsRecord, holdingsRecord.getId()); - bulkEditStatisticService.incrementSuccess(); - log.info("Update holdings record with id - {} by job id {}", holdingsRecord.getId(), jobId); - } catch (Exception e) { - log.info("Cannot update holdings record with id {}. Reason: {}", holdingsRecord.getId(), e.getMessage()); - bulkEditProcessingErrorsService.saveErrorInCSV(jobId, holdingsRecord.getId(), new BulkEditException(e.getMessage()), FilenameUtils.getName(jobExecution.getJobParameters().getString(FILE_NAME))); - } - }); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsJobConfig.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsJobConfig.java deleted file mode 100644 index f709c0f46..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsJobConfig.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import org.folio.dew.batch.JobCompletionNotificationListener; -import org.folio.dew.batch.bulkedit.jobs.JobConfigReaderHelper; -import org.folio.dew.domain.dto.Item; -import org.folio.dew.domain.dto.ItemFormat; -import org.folio.dew.repository.LocalFilesStorage; -import org.folio.dew.repository.S3CompatibleResource; -import org.springframework.batch.core.ItemWriteListener; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.configuration.annotation.StepScope; -import org.springframework.batch.core.job.builder.JobBuilder; -import org.springframework.batch.core.launch.support.RunIdIncrementer; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.StepBuilder; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemWriter; -import org.springframework.batch.item.file.FlatFileItemReader; -import org.springframework.batch.item.file.LineMapper; -import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.PlatformTransactionManager; - -import static org.apache.commons.lang3.ObjectUtils.isEmpty; -import static org.folio.dew.domain.dto.EntityType.ITEM; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.Constants.FILE_NAME; -import static org.folio.dew.utils.Constants.JOB_NAME_POSTFIX_SEPARATOR; - -@Configuration public class BulkEditUpdateItemRecordsJobConfig { - - @Bean public Job bulkEditUpdateItemRecordsJob(Step bulkEditUpdateItemRecordsStep, JobRepository jobRepository, - JobCompletionNotificationListener completionListener) { - return new JobBuilder(BULK_EDIT_UPDATE.getValue() + JOB_NAME_POSTFIX_SEPARATOR + ITEM.getValue(), jobRepository) - .incrementer(new RunIdIncrementer()) - .listener(completionListener) - .flow(bulkEditUpdateItemRecordsStep) - .end() - .build(); - } - - @Bean public Step bulkEditUpdateItemRecordsStep(ItemReader csvItemRecordsReader, - @Qualifier("bulkEditUpdateItemRecordsProcessor") ItemProcessor processor, - @Qualifier("updateItemRecordsWriter") ItemWriter writer, - @Qualifier("updateRecordWriteListener") ItemWriteListener updateRecordWriteListener, - JobRepository jobRepository, - PlatformTransactionManager transactionManager) { - return new StepBuilder("bulkEditUpdateRecordsStep", jobRepository) - .chunk(10, transactionManager) - .reader(csvItemRecordsReader) - .processor(processor) - .writer(writer) - .listener(updateRecordWriteListener) - .build(); - } - - @Bean @StepScope public FlatFileItemReader csvItemRecordsReader( - @Value("#{jobParameters['" + FILE_NAME + "']}") String fileName, - @Value("#{jobParameters['" + UPDATED_FILE_NAME + "']}") String updatedFileName, - LocalFilesStorage localFilesStorage) { - LineMapper itemLineMapper = JobConfigReaderHelper.createLineMapper(ItemFormat.class, ItemFormat.getItemFieldsArray()); - return new FlatFileItemReaderBuilder().name("itemReader") - .resource(new S3CompatibleResource<>(isEmpty(updatedFileName) ? fileName : updatedFileName, localFilesStorage)) - .linesToSkip(1) - .lineMapper(itemLineMapper) - .build(); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsProcessor.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsProcessor.java deleted file mode 100644 index ff7789d92..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsProcessor.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import static org.folio.dew.utils.Constants.FILE_NAME; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.dew.domain.dto.Item; -import org.folio.dew.domain.dto.ItemFormat; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.service.BulkEditParseService; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Log4j2 -@Component -@Qualifier("updateItemRecordsProcessor") -@RequiredArgsConstructor -@JobScope -public class BulkEditUpdateItemRecordsProcessor implements ItemProcessor { - - @Value("#{jobParameters['jobId']}") - private String jobId; - - @Value("#{jobParameters['identifierType']}") - private String identifierType; - - @Value("#{jobExecution}") - private JobExecution jobExecution; - - private final BulkEditParseService bulkEditParseService; - private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - - @Override - public Item process(ItemFormat itemFormat) throws Exception { - try { - return bulkEditParseService.mapItemFormatToItem(itemFormat); - } catch (Exception e) { - log.error("Error process item format {} : {}", itemFormat.getIdentifier(identifierType), e.getMessage()); - bulkEditProcessingErrorsService.saveErrorInCSV(jobId, itemFormat.getIdentifier(identifierType), new BulkEditException(e.getMessage()), FilenameUtils.getName(jobExecution.getJobParameters().getString(FILE_NAME))); - return null; - } - } - -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsWriter.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsWriter.java deleted file mode 100644 index e2a5f6ab5..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateItemRecordsWriter.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.dew.client.InventoryClient; -import org.folio.dew.domain.dto.Item; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.BulkEditStatisticService; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.Chunk; -import org.springframework.batch.item.ItemWriter; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import static org.folio.dew.utils.Constants.FILE_NAME; - -@Log4j2 -@Component -@Qualifier("updateItemRecordsWriter") -@RequiredArgsConstructor -@JobScope -public class BulkEditUpdateItemRecordsWriter implements ItemWriter { - - @Value("#{jobParameters['jobId']}") - private String jobId; - @Value("#{jobExecution}") - private JobExecution jobExecution; - - private final InventoryClient inventoryClient; - private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - private final BulkEditStatisticService bulkEditStatisticService; - - @Override - public void write(Chunk items) throws Exception { - items.forEach(item -> { - try { - inventoryClient.updateItem(item, item.getId()); - bulkEditStatisticService.incrementSuccess(); - log.info("Update item with id - {} by job id {}", item.getId(), jobId); - } catch (Exception e) { - log.info("Cannot update item with id {}. Reason: {}", item.getId(), e.getMessage()); - bulkEditProcessingErrorsService.saveErrorInCSV(jobId, item.getId(), new BulkEditException(e.getMessage()), FilenameUtils.getName(jobExecution.getJobParameters().getString(FILE_NAME))); - } - }); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsJobConfig.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsJobConfig.java deleted file mode 100644 index b89923873..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsJobConfig.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import org.folio.dew.batch.JobCompletionNotificationListener; -import org.folio.dew.batch.bulkedit.jobs.JobConfigReaderHelper; -import org.folio.dew.batch.bulkedit.jobs.updatejob.listeners.BulkEditUpdateUserRecordsListener; -import org.folio.dew.domain.dto.User; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.repository.LocalFilesStorage; -import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.repository.S3CompatibleResource; -import org.springframework.batch.core.ItemWriteListener; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.configuration.annotation.StepScope; -import org.springframework.batch.core.job.builder.JobBuilder; -import org.springframework.batch.core.launch.support.RunIdIncrementer; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.step.builder.StepBuilder; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemWriter; -import org.springframework.batch.item.file.FlatFileItemReader; -import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.InputStreamResource; -import org.springframework.transaction.PlatformTransactionManager; - -import java.io.IOException; - -import static org.apache.commons.lang3.ObjectUtils.isEmpty; -import static org.folio.dew.domain.dto.EntityType.USER; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.Constants.FILE_NAME; -import static org.folio.dew.utils.Constants.JOB_NAME_POSTFIX_SEPARATOR; - -@Configuration -public class BulkEditUpdateUserRecordsJobConfig { - - @Bean - public Job bulkEditUpdateUserRecordsJob( - Step bulkEditUpdateUserRecordsStep, - JobRepository jobRepository, - BulkEditUpdateUserRecordsListener updateUserRecordsListener, - JobCompletionNotificationListener completionListener) { - return new JobBuilder(BULK_EDIT_UPDATE.getValue() + JOB_NAME_POSTFIX_SEPARATOR + USER.getValue(), jobRepository) - .incrementer(new RunIdIncrementer()) - .listener(updateUserRecordsListener) - .listener(completionListener) - .flow(bulkEditUpdateUserRecordsStep) - .end() - .build(); - } - - @Bean - public Step bulkEditUpdateUserRecordsStep( - ItemReader csvUserRecordsReader, - @Qualifier("bulkEditUpdateUserRecordsProcessor") - ItemProcessor processor, - @Qualifier("updateUserRecordsWriter") ItemWriter writer, - @Qualifier("updateRecordWriteListener") ItemWriteListener updateRecordWriteListener, - JobRepository jobRepository, PlatformTransactionManager transactionManager) { - return new StepBuilder("bulkEditUpdateRecordsStep", jobRepository) - .chunk(10, transactionManager) - .reader(csvUserRecordsReader) - .processor(processor) - .writer(writer) - .listener(updateRecordWriteListener) - .build(); - } - - @Bean - @StepScope - public FlatFileItemReader csvUserRecordsReader( - @Value("#{jobParameters['" + FILE_NAME + "']}") String fileName, - @Value("#{jobParameters['" + UPDATED_FILE_NAME + "']}") String updatedFileName, - LocalFilesStorage localFilesStorage, RemoteFilesStorage remoteFilesStorage) - throws IOException { - var userLineMapper = JobConfigReaderHelper.createLineMapper(UserFormat.class, UserFormat.getUserFieldsArray()); - return new FlatFileItemReaderBuilder() - .name("userReader") - .resource(isEmpty(updatedFileName) ? new S3CompatibleResource<>(fileName, localFilesStorage) : new InputStreamResource(remoteFilesStorage.newInputStream(updatedFileName))) - .linesToSkip(1) - .lineMapper(userLineMapper) - .build(); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsProcessor.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsProcessor.java deleted file mode 100644 index 69faca304..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsProcessor.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import static org.folio.dew.utils.Constants.FILE_NAME; - -import org.apache.commons.io.FilenameUtils; -import org.folio.dew.domain.dto.User; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.service.BulkEditChangedRecordsService; -import org.folio.dew.service.BulkEditParseService; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.ItemProcessor; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; - -@Log4j2 -@Component -@Qualifier("updateUserRecordsProcessor") -@RequiredArgsConstructor -@JobScope -public class BulkEditUpdateUserRecordsProcessor implements ItemProcessor { - - @Value("#{jobParameters['jobId']}") - private String jobId; - @Value("#{jobExecution}") - private JobExecution jobExecution; - - private final BulkEditParseService bulkEditParseService; - private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - private final BulkEditChangedRecordsService changedRecordsService; - - @Override - public User process(UserFormat userFormat) throws Exception { - try { - var user = bulkEditParseService.mapUserFormatToUser(userFormat); - changedRecordsService.addUserId(user.getId(), jobId); - return user; - } catch (Exception e) { - log.info("Error process user format {} : {}", userFormat.getId(), e.getMessage()); - bulkEditProcessingErrorsService.saveErrorInCSV(jobId, userFormat.getBarcode(), new BulkEditException(e.getMessage()), FilenameUtils.getName(jobExecution.getJobParameters().getString(FILE_NAME))); - return null; - } - } - -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsWriter.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsWriter.java deleted file mode 100644 index 889413505..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/BulkEditUpdateUserRecordsWriter.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob; - -import static org.folio.dew.utils.Constants.FILE_NAME; -import static org.folio.dew.utils.Constants.NO_CHANGE_MESSAGE; - -import java.util.List; -import java.util.UUID; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.dew.client.UserClient; -import org.folio.dew.domain.dto.User; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.service.BulkEditChangedRecordsService; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.BulkEditRollBackService; -import org.folio.dew.service.BulkEditStatisticService; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.Chunk; -import org.springframework.batch.item.ItemWriter; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Log4j2 -@Component -@Qualifier("updateUserRecordsWriter") -@RequiredArgsConstructor -@JobScope -public class BulkEditUpdateUserRecordsWriter implements ItemWriter { - - @Value("#{jobParameters['jobId']}") - private String jobId; - @Value("#{jobExecution}") - private JobExecution jobExecution; - - private final UserClient userClient; - private final BulkEditRollBackService bulkEditRollBackService; - private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - private final BulkEditStatisticService bulkEditStatisticService; - private final BulkEditChangedRecordsService changedRecordsService; - - @Override - public void write(Chunk users) throws Exception { - users.forEach(user -> { - try { - var initialUser = userClient.getUserById(user.getId()); - initialUser.setMetadata(null); - if (initialUser.equals(user)) { - log.info("User with barcode={}: {}", user.getBarcode(), NO_CHANGE_MESSAGE); - bulkEditProcessingErrorsService.saveErrorInCSV(jobId, initialUser.getBarcode(), new BulkEditException(NO_CHANGE_MESSAGE), FilenameUtils.getName(jobExecution.getJobParameters().getString(FILE_NAME))); - changedRecordsService.removeUserId(user.getId(), jobId); - } else { - userClient.updateUser(user, user.getId()); - log.info("Update user with barcode={} by job id {}", user.getBarcode(), jobId); - bulkEditStatisticService.incrementSuccess(); - bulkEditRollBackService.putUserIdForJob(user.getId(), UUID.fromString(jobId)); - } - } catch (Exception e) { - log.error("Cannot update user with barcode={}. Reason: {}", user.getBarcode(), e.getMessage()); - bulkEditProcessingErrorsService.saveErrorInCSV(jobId, user.getBarcode(), new BulkEditException(e.getMessage()), FilenameUtils.getName(jobExecution.getJobParameters().getString(FILE_NAME))); - changedRecordsService.removeUserId(user.getId(), jobId); - } - }); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/listeners/BulkEditUpdateUserRecordsListener.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/listeners/BulkEditUpdateUserRecordsListener.java deleted file mode 100644 index db32ad022..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/listeners/BulkEditUpdateUserRecordsListener.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob.listeners; - -import lombok.RequiredArgsConstructor; -import org.folio.dew.service.BulkEditRollBackService; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobExecutionListener; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import java.util.UUID; - -@Component -@JobScope -@RequiredArgsConstructor -public class BulkEditUpdateUserRecordsListener implements JobExecutionListener { - - @Value("#{jobParameters['jobId']}") - private String jobId; - private final BulkEditRollBackService bulkEditRollBackService; - - @Override - public void beforeJob(JobExecution jobExecution) {} - - @Override - public void afterJob(JobExecution jobExecution) { - bulkEditRollBackService.cleanJobData(jobExecution.getExitStatus().getExitCode(), UUID.fromString(jobId)); - } -} diff --git a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/listeners/UpdateRecordWriteListener.java b/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/listeners/UpdateRecordWriteListener.java deleted file mode 100644 index a5bab8247..000000000 --- a/src/main/java/org/folio/dew/batch/bulkedit/jobs/updatejob/listeners/UpdateRecordWriteListener.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.updatejob.listeners; - -import static org.folio.dew.domain.dto.JobParameterNames.JOB_ID; -import static org.folio.dew.domain.dto.JobParameterNames.TOTAL_RECORDS; - -import java.util.Date; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; - -import lombok.extern.log4j.Log4j2; -import org.folio.de.entity.Job; -import org.folio.dew.config.kafka.KafkaService; -import org.folio.dew.domain.dto.EntityType; -import org.folio.dew.domain.dto.ExportType; -import org.folio.dew.domain.dto.Progress; -import org.folio.dew.service.BulkEditStatisticService; -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.ItemWriteListener; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.configuration.annotation.JobScope; -import org.springframework.batch.item.Chunk; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import lombok.RequiredArgsConstructor; - -@Component -@JobScope -@RequiredArgsConstructor -@Log4j2 -public class UpdateRecordWriteListener implements ItemWriteListener { - - private static final int BATCH_SIZE = 10; - - private final KafkaService kafka; - - @Value("#{jobExecution}") - private JobExecution jobExecution; - - private AtomicInteger processedRecords = new AtomicInteger(); - private final BulkEditStatisticService bulkEditUpdateStatisticService; - - @Override - public void afterWrite(Chunk items) { - var job = prepareJobWithProgress(); - kafka.send(KafkaService.Topic.JOB_UPDATE, job.getId().toString(), job); - } - - private Job prepareJobWithProgress() { - var totalRecords = jobExecution.getExecutionContext().getInt(TOTAL_RECORDS); - if (totalRecords < BATCH_SIZE) { - processedRecords.addAndGet(totalRecords); - } else { - processedRecords.addAndGet(BATCH_SIZE); - } - var job = new Job(); - job.setId(UUID.fromString(jobExecution.getJobParameters().getString(JOB_ID))); - job.setType(ExportType.BULK_EDIT_UPDATE); - job.setEntityType(EntityType.fromValue(jobExecution.getJobInstance().getJobName().split("-")[1])); - job.setBatchStatus(BatchStatus.STARTED); - job.setStartTime(new Date()); - job.setCreatedDate(new Date()); - job.setEndTime(new Date()); - job.setUpdatedDate(new Date()); - - Progress progress = new Progress(); - progress.setTotal(totalRecords); - progress.setProcessed(processedRecords.get()); - progress.setProgress(getProgressBarValue(processedRecords.get(), totalRecords)); - - var statistic = bulkEditUpdateStatisticService.getStatistic(); - progress.setSuccess(statistic.getSuccess()); - job.setProgress(progress); - return job; - } - - private int getProgressBarValue(int processed, int totalRecords) { - if (totalRecords < BATCH_SIZE) { - return 90; - } - var progress = ((double) processed / totalRecords) * 100; - return progress < 100 ? (int) progress : 99; - } -} diff --git a/src/main/java/org/folio/dew/controller/BulkEditController.java b/src/main/java/org/folio/dew/controller/BulkEditController.java index 86220ac2d..e4605bd36 100644 --- a/src/main/java/org/folio/dew/controller/BulkEditController.java +++ b/src/main/java/org/folio/dew/controller/BulkEditController.java @@ -2,93 +2,41 @@ import static java.lang.String.format; import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.folio.dew.domain.dto.EntityType.HOLDINGS_RECORD; -import static org.folio.dew.domain.dto.EntityType.ITEM; -import static org.folio.dew.domain.dto.EntityType.USER; import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_IDENTIFIERS; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.PREVIEW_FILE_NAME; -import static org.folio.dew.domain.dto.JobParameterNames.QUERY; import static org.folio.dew.domain.dto.JobParameterNames.TEMP_LOCAL_FILE_PATH; import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_FILE_PATH; import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_MARC_PATH; import static org.folio.dew.domain.dto.JobParameterNames.TEMP_LOCAL_MARC_PATH; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.BulkEditProcessorHelper.getMatchPattern; -import static org.folio.dew.utils.BulkEditProcessorHelper.resolveIdentifier; import static org.folio.dew.utils.Constants.BULKEDIT_DIR_NAME; -import static org.folio.dew.utils.Constants.CSV_EXTENSION; import static org.folio.dew.utils.Constants.EXPORT_TYPE; import static org.folio.dew.utils.Constants.FILE_NAME; import static org.folio.dew.utils.Constants.FILE_UPLOAD_ERROR; -import static org.folio.dew.utils.Constants.IDENTIFIER_TYPE; -import static org.folio.dew.utils.Constants.INITIAL_PREFIX; import static org.folio.dew.utils.Constants.MARC_RECORDS; import static org.folio.dew.utils.Constants.MATCHED_RECORDS; import static org.folio.dew.utils.Constants.PATH_SEPARATOR; import static org.folio.dew.utils.Constants.TEMP_IDENTIFIERS_FILE_NAME; import static org.folio.dew.utils.Constants.TOTAL_CSV_LINES; -import static org.folio.dew.utils.Constants.PREVIEW_PREFIX; import static org.folio.dew.utils.Constants.getWorkingDirectory; import static org.folio.dew.utils.CsvHelper.countLines; import static org.folio.dew.utils.SystemHelper.getTempDirWithSeparatorSuffix; import static org.folio.spring.scope.FolioExecutionScopeExecutionContextManager.getRunnableWithCurrentFolioContext; -import com.opencsv.CSVReader; -import io.swagger.annotations.ApiParam; import jakarta.annotation.PostConstruct; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDate; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.UUID; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.StringUtils; import org.folio.de.entity.JobCommand; import org.folio.dew.batch.ExportJobManagerSync; -import org.folio.dew.client.HoldingClient; -import org.folio.dew.client.InventoryClient; -import org.folio.dew.client.UserClient; -import org.folio.dew.domain.dto.Errors; -import org.folio.dew.domain.dto.HoldingsContentUpdateCollection; -import org.folio.dew.domain.dto.HoldingsFormat; -import org.folio.dew.domain.dto.HoldingsRecordCollection; -import org.folio.dew.domain.dto.IdentifierType; -import org.folio.dew.domain.dto.ItemCollection; -import org.folio.dew.domain.dto.ItemContentUpdateCollection; -import org.folio.dew.domain.dto.ItemFormat; -import org.folio.dew.domain.dto.UserCollection; -import org.folio.dew.domain.dto.UserContentUpdateCollection; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.error.FileOperationException; -import org.folio.dew.error.NonSupportedEntityException; import org.folio.dew.error.NotFoundException; import org.folio.dew.repository.LocalFilesStorage; -import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.service.BulkEditItemContentUpdateService; -import org.folio.dew.service.BulkEditParseService; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.BulkEditRollBackService; import org.folio.dew.service.JobCommandsReceiverService; -import org.folio.dew.service.UpdatesResult; -import org.folio.dew.service.mapper.HoldingsMapper; -import org.folio.dew.service.update.BulkEditHoldingsContentUpdateService; -import org.folio.dew.service.update.BulkEditUserContentUpdateService; -import org.folio.dew.utils.CsvHelper; import org.folio.spring.FolioExecutionContext; import org.folio.spring.FolioModuleMetadata; import org.openapitools.api.JobIdApi; @@ -97,17 +45,9 @@ import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.integration.launch.JobLaunchRequest; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.DescriptiveResource; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -119,23 +59,11 @@ public class BulkEditController implements JobIdApi { private static final String JOB_COMMAND_NOT_FOUND_ERROR = "JobCommand with id %s doesn't exist."; - private static final String FAILED_TO_READ_FILE_ERROR = "Failed to read %s for job id %s, reason: %s"; private static final boolean JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE = false; - private final UserClient userClient; - private final InventoryClient inventoryClient; - private final HoldingClient holdingClient; private final JobCommandsReceiverService jobCommandsReceiverService; private final ExportJobManagerSync exportJobManagerSync; - private final BulkEditRollBackService bulkEditRollBackService; - private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService; private final List jobs; - private final BulkEditItemContentUpdateService itemContentUpdateService; - private final BulkEditUserContentUpdateService userContentUpdateService; - private final BulkEditHoldingsContentUpdateService holdingsContentUpdateService; - private final BulkEditParseService bulkEditParseService; - private final HoldingsMapper holdingsMapper; - private final RemoteFilesStorage remoteFilesStorage; private final LocalFilesStorage localFilesStorage; private final FolioModuleMetadata folioModuleMetadata; private final FolioExecutionContext folioExecutionContext; @@ -149,175 +77,6 @@ public void postConstruct() { workDir = getWorkingDirectory(springApplicationName, BULKEDIT_DIR_NAME); } - @Override - public ResponseEntity postItemContentUpdates(@ApiParam(value = "UUID of the JobCommand",required=true) @PathVariable("jobId") UUID jobId,@ApiParam(value = "" ,required=true ) @Valid @RequestBody ItemContentUpdateCollection contentUpdateCollection,@ApiParam(value = "The numbers of records to return") @Valid @RequestParam(value = "limit", required = false) Integer limit) { - var jobCommand = prepareForContentUpdates(jobId); - log.info("postItemContentUpdates: jobCommand={}.", jobCommand); - var updatesResult = itemContentUpdateService.processContentUpdates(jobCommand, contentUpdateCollection); - log.info("postItemContentUpdates: jobCommand={}; updatesResult size={}.", jobCommand, updatesResult.getEntitiesForPreview().size()); - jobCommandsReceiverService.updateJobCommand(jobCommand); - return new ResponseEntity<>(prepareItemContentUpdateResponse(updatesResult, limit), HttpStatus.OK); - } - - @Override - public ResponseEntity postUserContentUpdates(@ApiParam(value = "UUID of the JobCommand",required=true) @PathVariable("jobId") UUID jobId, @ApiParam(value = "" ,required=true ) @Valid @RequestBody UserContentUpdateCollection contentUpdateCollection, @ApiParam(value = "The numbers of records to return") @Valid @RequestParam(value = "limit", required = false) Integer limit) { - var jobCommand = prepareForContentUpdates(jobId); - log.info("postUserContentUpdates: jobCommand={}.", jobCommand); - var updatesResult = userContentUpdateService.process(jobCommand, contentUpdateCollection); - log.info("postUserContentUpdate: {} users", updatesResult.getEntitiesForPreview().size()); - jobCommandsReceiverService.updateJobCommand(jobCommand); - return new ResponseEntity<>(prepareUserContentUpdateResponse(updatesResult, limit), HttpStatus.OK); - } - - @Override - public ResponseEntity postHoldingsContentUpdates(@ApiParam(value = "UUID of the JobCommand",required=true) @PathVariable("jobId") UUID jobId, @ApiParam(value = "" ,required=true ) @Valid @RequestBody HoldingsContentUpdateCollection contentUpdateCollection, @ApiParam(value = "The numbers of records to return") @Valid @RequestParam(value = "limit", required = false) Integer limit) { - var jobCommand = prepareForContentUpdates(jobId); - log.info("postHoldingsContentUpdates: jobCommand={}.", jobCommand); - var updatesResult = holdingsContentUpdateService.process(jobCommand, contentUpdateCollection); - log.info("postHoldingsContentUpdates: jobCommand={}; updatesResult size={}.", jobCommand, updatesResult.getEntitiesForPreview().size()); - jobCommandsReceiverService.updateJobCommand(jobCommand); - return new ResponseEntity<>(prepareHoldingsContentUpdateResponse(updatesResult, limit), HttpStatus.OK); - } - - private JobCommand prepareForContentUpdates(UUID jobId) { - bulkEditProcessingErrorsService.removeTemporaryErrorStorage(); - var jobCommand = getJobCommandById(jobId.toString()); - if (nonNull(jobCommand.getIdentifierType())) { - jobCommand.setJobParameters(new JobParametersBuilder(jobCommand.getJobParameters()) - .addString(IDENTIFIER_TYPE, jobCommand.getIdentifierType().getValue()) - .toJobParameters()); - } - return jobCommand; - } - - @Override - public ResponseEntity getPreviewUsersByJobId(@ApiParam(value = "UUID of the JobCommand", required = true) @PathVariable("jobId") UUID jobId, @NotNull @ApiParam(value = "The numbers of items to return", required = true) @Valid @RequestParam(value = "limit") Integer limit) { - var jobCommand = getJobCommandById(jobId.toString()); - log.info("getPreviewUsersByJobId:: with jobExportType={}", jobCommand.getExportType()); - if (BULK_EDIT_IDENTIFIERS == jobCommand.getExportType()) { - var fileName = jobCommand.getId() + PATH_SEPARATOR + FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION; - try { - var userFormats = CsvHelper.readRecordsFromRemoteFilesStorage(remoteFilesStorage, fileName, limit, UserFormat.class); - log.info("getPreviewUsersByJobId:: Reading of file {} complete, number of userFormats: {}", fileName, userFormats.size()); - var users = userFormats.stream() - .map(bulkEditParseService::mapUserFormatToUser) - .collect(Collectors.toList()); - return new ResponseEntity<>(new UserCollection().users(users).totalRecords(users.size()), HttpStatus.OK); - } catch (Exception e) { - var msg = String.format(FAILED_TO_READ_FILE_ERROR, fileName, jobCommand.getId(), e.getMessage()); - log.error(msg); - return new ResponseEntity<>(new UserCollection().users(Collections.emptyList()).totalRecords(0), HttpStatus.OK); - } - } else { - return new ResponseEntity<>(userClient.getUserByQuery(buildPreviewUsersQueryFromJobCommand(jobCommand, limit), limit), HttpStatus.OK); - } - } - - @Override public ResponseEntity getPreviewItemsByJobId(UUID jobId, Integer limit) { - var jobCommand = getJobCommandById(jobId.toString()); - log.info("getPreviewItemsByJobId:: with jobExportType={}", jobCommand.getExportType()); - if (BULK_EDIT_IDENTIFIERS == jobCommand.getExportType()) { - var fileName = jobCommand.getId() + PATH_SEPARATOR + FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION; - try { - var itemsFormat = CsvHelper.readRecordsFromRemoteFilesStorage(remoteFilesStorage, fileName, limit, ItemFormat.class); - log.info("getPreviewItemsByJobId:: Reading of file {} complete, number of itemsFormat: {}", fileName, itemsFormat.size()); - var items = itemsFormat.stream() - .map(bulkEditParseService::mapItemFormatToItem) - .collect(Collectors.toList()); - return new ResponseEntity<>(new ItemCollection().items(items).totalRecords(items.size()), HttpStatus.OK); - } catch (Exception e) { - var msg = String.format(FAILED_TO_READ_FILE_ERROR, fileName, jobCommand.getId(), e.getMessage()); - log.error(msg); - return new ResponseEntity<>(new ItemCollection().items(Collections.emptyList()).totalRecords(0), HttpStatus.OK); - } - } else { - return new ResponseEntity<>(inventoryClient.getItemByQuery(buildPreviewQueryFromJobCommand(jobCommand, limit), limit), HttpStatus.OK); - } - } - - @Override - public ResponseEntity getPreviewHoldingsByJobId(UUID jobId, Integer limit) { - var jobCommand = getJobCommandById(jobId.toString()); - log.info("getPreviewHoldingsByJobId:: with jobExportType={}", jobCommand.getExportType()); - if (BULK_EDIT_IDENTIFIERS == jobCommand.getExportType()) { - var fileName = jobCommand.getId() + PATH_SEPARATOR + FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION; - try { - var holdingsFormat = CsvHelper.readRecordsFromRemoteFilesStorage(remoteFilesStorage, fileName, limit, HoldingsFormat.class); - log.info("getPreviewHoldingsByJobId:: Reading of file {} complete, number of holdingsFormat: {}", fileName, holdingsFormat.size()); - var holdings = holdingsFormat.stream() - .map(holdingsMapper::mapToHoldingsRecord) - .collect(Collectors.toList()); - return new ResponseEntity<>(new HoldingsRecordCollection().holdingsRecords(holdings).totalRecords(holdings.size()), HttpStatus.OK); - } catch (Exception e) { - var msg = String.format(FAILED_TO_READ_FILE_ERROR, fileName, jobCommand.getId(), e.getMessage()); - log.error(msg); - return new ResponseEntity<>(new HoldingsRecordCollection().holdingsRecords(Collections.emptyList()).totalRecords(0), HttpStatus.OK); - } - } else { - return new ResponseEntity<>(holdingClient.getHoldingsByQuery(buildPreviewQueryFromJobCommand(jobCommand, limit), limit), HttpStatus.OK); - } - } - - @Override - public ResponseEntity downloadItemsPreviewByJobId(@ApiParam(value = "UUID of the JobCommand", required = true) @PathVariable("jobId") UUID jobId) { - var jobCommand = getJobCommandById(jobId.toString()); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); - try { - var updatedFileName = FilenameUtils.getName(jobCommand.getJobParameters().getString(PREVIEW_FILE_NAME)); - var updatedFullPath = FilenameUtils.getFullPath(jobCommand.getJobParameters().getString(PREVIEW_FILE_NAME)); - var updatedFilePath = updatedFullPath + updatedFileName; - var content = localFilesStorage.readAllBytes(updatedFilePath); - ByteArrayResource updatedFileResource = new ByteArrayResource(content); - headers.setContentLength(content.length); - headers.setContentDispositionFormData(updatedFileName, updatedFileName); - return ResponseEntity.ok().headers(headers).body(updatedFileResource); - } catch (Exception e) { - log.error("Something went wrong during downloadItemsPreviewByJobId."); - return ResponseEntity.internalServerError().body(new DescriptiveResource(e.getMessage())); - } - } - - @Override - public ResponseEntity downloadUsersPreviewByJobId(@ApiParam(value = "UUID of the JobCommand", required = true) @PathVariable("jobId") UUID jobId) { - return downloadPreviewByJobId(jobId); - } - - @Override - public ResponseEntity downloadHoldingsPreviewByJobId(@ApiParam(value = "UUID of the JobCommand", required = true) @PathVariable("jobId") UUID jobId) { - return downloadPreviewByJobId(jobId); - } - - private ResponseEntity downloadPreviewByJobId(UUID jobId) { - var jobCommand = getJobCommandById(jobId.toString()); - var fileName = jobCommand.getJobParameters().getString(PREVIEW_FILE_NAME); - if (nonNull(fileName)) { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); - try (InputStream is = remoteFilesStorage.newInputStream(fileName)) { - var updatedUsersResource = new ByteArrayResource(is.readAllBytes()); - headers.setContentLength(updatedUsersResource.contentLength()); - headers.setContentDispositionFormData(fileName, fileName); - return ResponseEntity.ok().headers(headers).body(updatedUsersResource); - } catch (Exception e) { - log.error("Something went wrong during downloadPreviewByJobId."); - return ResponseEntity.internalServerError().body(new DescriptiveResource(e.getMessage())); - } - } - log.error("Preview is not available"); - throw new NotFoundException("Preview is not available"); - } - - @Override - public ResponseEntity getErrorsPreviewByJobId(@ApiParam(value = "UUID of the JobCommand", required = true) @PathVariable("jobId") UUID jobId, @NotNull @ApiParam(value = "The numbers of users to return", required = true) @Valid @RequestParam(value = "limit") Integer limit) { - var jobCommand = getJobCommandById(jobId.toString()); - var fileName = jobCommand.getId() + PATH_SEPARATOR + FilenameUtils.getName(jobCommand.getJobParameters().getString(FILE_NAME)); - log.info("downloadHoldingsPreviewByJobId:: fileName={}", fileName); - - var errors = bulkEditProcessingErrorsService.readErrorsFromCSV(jobId.toString(), fileName, limit); - return new ResponseEntity<>(errors, HttpStatus.OK); - } - @Override public ResponseEntity uploadCsvFile(UUID jobId, MultipartFile file) { log.info("uploadCsvFile:: for jobId={} ", jobId); @@ -339,23 +98,18 @@ public ResponseEntity uploadCsvFile(UUID jobId, MultipartFile file) { } prepareJobParameters(jobCommand, uploadedPath, tempIdentifiersFile); jobCommandsReceiverService.updateJobCommand(jobCommand); - if (isBulkEditUpdate(jobCommand) && jobCommand.getEntityType() == USER) { - localFilesStorage.write(workDir + jobId + PATH_SEPARATOR + INITIAL_PREFIX + file.getOriginalFilename(), file.getBytes()); - } log.info("File {} has been uploaded successfully.", file.getOriginalFilename()); - if (!isBulkEditUpdate(jobCommand)) { - var job = getBulkEditJob(jobCommand); - var jobLaunchRequest = new JobLaunchRequest(job, jobCommand.getJobParameters()); - log.info("Launching bulk edit identifiers job."); - new Thread(getRunnableWithCurrentFolioContext(() -> { - try { - exportJobManagerSync.launchJob(jobLaunchRequest); - } catch (JobExecutionException e) { - String errorMessage = format(FILE_UPLOAD_ERROR, e.getMessage()); - log.error(errorMessage); - } - })).start(); - } + var job = getBulkEditJob(jobCommand); + var jobLaunchRequest = new JobLaunchRequest(job, jobCommand.getJobParameters()); + log.info("Launching bulk edit identifiers job."); + new Thread(getRunnableWithCurrentFolioContext(() -> { + try { + exportJobManagerSync.launchJob(jobLaunchRequest); + } catch (JobExecutionException e) { + String errorMessage = format(FILE_UPLOAD_ERROR, e.getMessage()); + log.error(errorMessage); + } + })).start(); var numberOfLines = jobCommand.getJobParameters().getLong(TOTAL_CSV_LINES); return new ResponseEntity<>(Long.toString(isNull(numberOfLines) ? 0 : numberOfLines), HttpStatus.OK); } catch (Exception e) { @@ -376,13 +130,6 @@ private String saveTemporaryIdentifiersFile(UUID jobId, MultipartFile file) thro return tempFilePath; } - @Override - public ResponseEntity rollBackCsvFile(UUID jobId) { - log.info("rollBackCsvFile:: for jobId={}", jobId.toString()); - var message = bulkEditRollBackService.stopAndRollBackJobExecutionByJobId(jobId); - return new ResponseEntity<>(message, HttpStatus.OK); - } - @Override public ResponseEntity startJob(UUID jobId) { var jobCommand = getJobCommandById(jobId.toString()); @@ -406,7 +153,7 @@ public ResponseEntity startJob(UUID jobId) { } private Job getBulkEditJob(JobCommand jobCommand) { - var jobName = BULK_EDIT_IDENTIFIERS == jobCommand.getExportType() || BULK_EDIT_UPDATE == jobCommand.getExportType() ? + var jobName = BULK_EDIT_IDENTIFIERS == jobCommand.getExportType() ? jobCommand.getExportType().getValue() + "-" + jobCommand.getEntityType() : jobCommand.getExportType().getValue(); return jobs.stream() @@ -419,12 +166,12 @@ private void prepareJobParameters(JobCommand jobCommand, String uploadedPath, St var paramsBuilder = new JobParametersBuilder(jobCommand.getJobParameters()); ofNullable(tempIdentifiersFile).ifPresent(path -> paramsBuilder.addString(TEMP_IDENTIFIERS_FILE_NAME, path, JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE)); paramsBuilder.addString(FILE_NAME, uploadedPath, JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); - paramsBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, uploadedPath, isBulkEditUpdate(jobCommand)), JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); - var fileName = jobCommand.getId() + PATH_SEPARATOR + (isBulkEditUpdate(jobCommand) ? EMPTY : LocalDate.now() + MATCHED_RECORDS) + FilenameUtils.getBaseName(uploadedPath); + paramsBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, uploadedPath), JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); + var fileName = jobCommand.getId() + PATH_SEPARATOR + LocalDate.now() + MATCHED_RECORDS + FilenameUtils.getBaseName(uploadedPath); paramsBuilder.addString(TEMP_OUTPUT_FILE_PATH, workDir + fileName, JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); paramsBuilder.addString(TEMP_LOCAL_FILE_PATH, getTempDirWithSeparatorSuffix() + springApplicationName + PATH_SEPARATOR + fileName, JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); paramsBuilder.addString(EXPORT_TYPE, jobCommand.getExportType().getValue(), JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); - var marcFileName = jobCommand.getId() + PATH_SEPARATOR + (isBulkEditUpdate(jobCommand) ? EMPTY : LocalDate.now() + MARC_RECORDS) + FilenameUtils.getBaseName(uploadedPath); + var marcFileName = jobCommand.getId() + PATH_SEPARATOR + LocalDate.now() + MARC_RECORDS + FilenameUtils.getBaseName(uploadedPath); paramsBuilder.addString(TEMP_OUTPUT_MARC_PATH, workDir + marcFileName); paramsBuilder.addString(TEMP_LOCAL_MARC_PATH, getTempDirWithSeparatorSuffix() + springApplicationName + PATH_SEPARATOR + marcFileName, JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); ofNullable(jobCommand.getIdentifierType()).ifPresent(type -> @@ -434,10 +181,6 @@ private void prepareJobParameters(JobCommand jobCommand, String uploadedPath, St jobCommand.setJobParameters(paramsBuilder.toJobParameters()); } - private boolean isBulkEditUpdate(JobCommand jobCommand) { - return jobCommand.getExportType() == BULK_EDIT_UPDATE; - } - private JobCommand getJobCommandById(String jobId) { var jobCommandOptional = jobCommandsReceiverService.getBulkEditJobCommandById(jobId); if (jobCommandOptional.isEmpty()) { @@ -448,136 +191,4 @@ private JobCommand getJobCommandById(String jobId) { return jobCommandOptional.get(); } - private ItemCollection prepareItemContentUpdateResponse(UpdatesResult updatesResult, Integer limit) { - var items = updatesResult.getEntitiesForPreview().stream() - .limit(isNull(limit) ? Integer.MAX_VALUE : limit) - .map(bulkEditParseService::mapItemFormatToItem) - .collect(Collectors.toList()); - return new ItemCollection().items(items).totalRecords(updatesResult.getTotal()); - } - - private UserCollection prepareUserContentUpdateResponse(UpdatesResult updatesResult, Integer limit) { - var users = updatesResult.getEntitiesForPreview().stream() - .limit(isNull(limit) ? Integer.MAX_VALUE : limit) - .map(bulkEditParseService::mapUserFormatToUser) - .collect(Collectors.toList()); - return new UserCollection().users(users).totalRecords(updatesResult.getTotal()); - } - - private HoldingsRecordCollection prepareHoldingsContentUpdateResponse(UpdatesResult updatesResult, Integer limit) { - var holdingsRecords = updatesResult.getEntitiesForPreview().stream() - .limit(isNull(limit) ? Integer.MAX_VALUE : limit) - .map(holdingsMapper::mapToHoldingsRecord) - .collect(Collectors.toList()); - return new HoldingsRecordCollection().holdingsRecords(holdingsRecords).totalRecords(updatesResult.getTotal()); - } - - private String buildPreviewUsersQueryFromJobCommand(JobCommand jobCommand, int limit) { - if (isBulkEditUpdate(jobCommand)) { - ofNullable(jobCommand.getJobParameters().getString(FILE_NAME)).ifPresent(filename -> { - var basename = FilenameUtils.getBaseName(filename); - if (!basename.startsWith(INITIAL_PREFIX)) { - jobCommand.setJobParameters(new JobParametersBuilder(jobCommand.getJobParameters()).addString(FILE_NAME, - filename.replace(basename, INITIAL_PREFIX + basename)).toJobParameters()); - } - }); - } - return buildPreviewQueryFromJobCommand(jobCommand, limit); - } - - private String buildPreviewQueryFromJobCommand(JobCommand jobCommand, int limit) { - switch(jobCommand.getExportType()) { - case BULK_EDIT_UPDATE: - var query = buildPreviewQueryFromCsv(jobCommand, limit); - return query.replace("()", "(default)"); - case BULK_EDIT_QUERY: - return jobCommand.getJobParameters().getString(QUERY); - default: - throw new NonSupportedEntityException(format("Non-supported export type: %s", jobCommand.getExportType())); - } - } - - private String buildPreviewQueryFromCsv(JobCommand jobCommand, int limit) { - var fileName = extractFileName(jobCommand); - if (StringUtils.isEmpty(fileName)) throw new FileOperationException("File for preview is not present or was not uploaded"); - if (!fileName.contains(CSV_EXTENSION)) fileName += CSV_EXTENSION; - try { - Reader inputReader; - var minioFileName = nonNull(jobCommand.getJobParameters().getString(UPDATED_FILE_NAME)) ? jobCommand.getId() + PATH_SEPARATOR + FilenameUtils.getName(fileName) : PREVIEW_PREFIX + FilenameUtils.getName(fileName); - if (remoteFilesStorage.containsFile(minioFileName)) { - inputReader = new InputStreamReader(remoteFilesStorage.newInputStream(minioFileName)); - } else { - inputReader = new InputStreamReader(localFilesStorage.newInputStream(fileName)); - } - try (var reader = new CSVReader(inputReader)) { - var values = reader.readAll().stream() - .skip(getNumberOfLinesToSkip(jobCommand)) - .limit(limit) - .map(line -> extractIdentifiersFromLine(line, jobCommand)) - .map(identifier -> String.format("\"%s\"", identifier)) - .collect(Collectors.joining(" OR ", "(", ")")); - var identifierType = getIdentifierType(jobCommand); - return format(getMatchPattern(identifierType), resolveIdentifier(identifierType), values); - } - - } catch (Exception e) { - throw new FileOperationException(format("Failed to read %s file, reason: %s", fileName, e.getMessage())); - } - } - - private String getIdentifierType(JobCommand jobCommand) { - if (jobCommand.getEntityType() == HOLDINGS_RECORD) { - return IdentifierType.ID.getValue(); - } - return jobCommand.getIdentifierType().getValue(); - } - - private String extractIdentifiersFromLine(String[] line, JobCommand jobCommand) { - var identifierIndex = getIdentifierIndex(jobCommand); - if (line.length > identifierIndex + 1) { - return line[identifierIndex]; - } else if (line.length == 1) { - return line[0]; - } - return EMPTY; - } - - private int getNumberOfLinesToSkip(JobCommand jobCommand) { - if (BULK_EDIT_UPDATE == jobCommand.getExportType()) { - return nonNull(jobCommand.getJobParameters().getString(UPDATED_FILE_NAME)) ? 1 : 0; - } - return 0; - } - - private String extractFileName(JobCommand jobCommand) { - if (isItemUpdatePreview(jobCommand) || isHoldingUpdatePreview(jobCommand)) { - return jobCommand.getJobParameters().getString(UPDATED_FILE_NAME); - } - var fileProperty = isUserUpdatePreview(jobCommand) ? TEMP_OUTPUT_FILE_PATH : FILE_NAME; - return jobCommand.getJobParameters().getString(fileProperty); - } - - private boolean isHoldingUpdatePreview(JobCommand jobCommand) { - return jobCommand.getExportType() == BULK_EDIT_UPDATE && jobCommand.getEntityType() == HOLDINGS_RECORD; - } - - private boolean isUserUpdatePreview(JobCommand jobCommand) { - return jobCommand.getExportType() == BULK_EDIT_UPDATE && jobCommand.getEntityType() == USER; - } - - private boolean isItemUpdatePreview(JobCommand jobCommand) { - return jobCommand.getExportType() == BULK_EDIT_UPDATE && jobCommand.getEntityType() == ITEM; - } - - private int getIdentifierIndex(JobCommand jobCommand) { - if (USER == jobCommand.getEntityType()) { - return Arrays.asList(UserFormat.getUserFieldsArray()).indexOf(resolveIdentifier(jobCommand.getIdentifierType().getValue())); - } else if (ITEM == jobCommand.getEntityType()) { - return Arrays.asList(ItemFormat.getItemFieldsArray()).indexOf(resolveIdentifier(jobCommand.getIdentifierType().getValue())); - } else if (HOLDINGS_RECORD == jobCommand.getEntityType()) { - return Arrays.asList(HoldingsFormat.getHoldingsFieldsArray()).indexOf(IdentifierType.ID.getValue().toLowerCase()); - } else { - throw new NonSupportedEntityException(format("Non-supported entity type: %s", jobCommand.getEntityType())); - } - } } diff --git a/src/main/java/org/folio/dew/service/BulkEditChangedRecordsService.java b/src/main/java/org/folio/dew/service/BulkEditChangedRecordsService.java deleted file mode 100644 index 28db145b6..000000000 --- a/src/main/java/org/folio/dew/service/BulkEditChangedRecordsService.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.folio.dew.service; - -import org.springframework.stereotype.Service; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -@Service -public class BulkEditChangedRecordsService { - private final Map> changedIdsMap = new ConcurrentHashMap<>(); - - public void addUserId(String userId, String jobId) { - var ids = changedIdsMap.computeIfAbsent(jobId, key -> new HashSet<>()); - ids.add(userId); - } - - public void removeUserId(String userId, String jobId) { - var ids = changedIdsMap.getOrDefault(jobId, new HashSet<>()); - ids.remove(userId); - } - - public Set fetchChangedUserIds(String jobId) { - return changedIdsMap.remove(jobId); - } -} diff --git a/src/main/java/org/folio/dew/service/BulkEditItemContentUpdateService.java b/src/main/java/org/folio/dew/service/BulkEditItemContentUpdateService.java deleted file mode 100644 index 78666ab05..000000000 --- a/src/main/java/org/folio/dew/service/BulkEditItemContentUpdateService.java +++ /dev/null @@ -1,264 +0,0 @@ -package org.folio.dew.service; - -import static java.time.ZoneOffset.UTC; -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; -import static org.apache.commons.lang3.ObjectUtils.isEmpty; -import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.folio.dew.domain.dto.ItemContentUpdate.ActionEnum.CLEAR_FIELD; -import static org.folio.dew.domain.dto.ItemContentUpdate.ActionEnum.REPLACE_WITH; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.PERMANENT_LOAN_TYPE; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.PERMANENT_LOCATION; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.STATUS; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.TEMPORARY_LOCATION; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.PREVIEW_FILE_NAME; -import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_FILE_PATH; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.BulkEditProcessorHelper.dateToString; -import static org.folio.dew.utils.Constants.ARRAY_DELIMITER; -import static org.folio.dew.utils.Constants.COMMA; -import static org.folio.dew.utils.Constants.BULKEDIT_DIR_NAME; -import static org.folio.dew.utils.Constants.CSV_EXTENSION; -import static org.folio.dew.utils.Constants.FILE_NAME; -import static org.folio.dew.utils.Constants.IDENTIFIER_TYPE; -import static org.folio.dew.utils.Constants.NO_CHANGE_MESSAGE; -import static org.folio.dew.utils.Constants.PATH_SEPARATOR; -import static org.folio.dew.utils.Constants.PREVIEW_PREFIX; -import static org.folio.dew.utils.Constants.STATUS_FIELD_CAN_NOT_CLEARED; -import static org.folio.dew.utils.Constants.STATUS_VALUE_NOT_ALLOWED; -import static org.folio.dew.utils.Constants.UPDATED_PREFIX; -import static org.folio.dew.utils.Constants.getWorkingDirectory; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.de.entity.JobCommand; -import org.folio.dew.domain.dto.ItemContentUpdate; -import org.folio.dew.domain.dto.ItemContentUpdateCollection; -import org.folio.dew.domain.dto.ItemFormat; -import org.folio.dew.error.FileOperationException; -import org.folio.dew.repository.LocalFilesStorage; -import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.utils.CsvHelper; -import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import jakarta.annotation.PostConstruct; -import java.time.LocalDateTime; -import java.util.Date; -import java.util.List; -import java.util.Objects; - -@Component -@RequiredArgsConstructor -@Log4j2 -public class BulkEditItemContentUpdateService { - private String workdir; - - @Value("${spring.application.name}") - private String springApplicationName; - - private final ItemReferenceService itemReferenceService; - private final RemoteFilesStorage remoteFilesStorage; - private final LocalFilesStorage localFilesStorage; - private final BulkEditProcessingErrorsService errorsService; - - @PostConstruct - public void postConstruct() { - workdir = getWorkingDirectory(springApplicationName, BULKEDIT_DIR_NAME); - } - - public UpdatesResult processContentUpdates(JobCommand jobCommand, ItemContentUpdateCollection contentUpdates) { - var outputFileName = workdir + jobCommand.getId() + PATH_SEPARATOR + UPDATED_PREFIX + FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION; - try { - log.info("Processing content updates for job id {}", jobCommand.getId()); - localFilesStorage.delete(outputFileName); - remoteFilesStorage.downloadObject(jobCommand.getId() + PATH_SEPARATOR + FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION, outputFileName); - var updateResult = new UpdatesResult(); - var records = CsvHelper.readRecordsFromStorage(localFilesStorage, outputFileName, ItemFormat.class, true); - log.info("Reading of file {} complete, number of itemFormats: {}", outputFileName, records.size()); - updateResult.setTotal(records.size()); - var contentUpdated = applyContentUpdates(records, contentUpdates, jobCommand); - log.info("Finished processing content updates: {} records, {} preview", contentUpdated.getUpdated().size(), contentUpdated.getPreview().size()); - updateResult.setEntitiesForPreview(contentUpdated.getPreview()); - var previewOutputFileName = workdir + jobCommand.getId() + PATH_SEPARATOR + PREVIEW_PREFIX + FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION; - saveResultToFile(contentUpdated.getPreview(), jobCommand, previewOutputFileName, PREVIEW_FILE_NAME); - saveResultToFile(contentUpdated.getUpdated(), jobCommand, outputFileName, UPDATED_FILE_NAME); - jobCommand.setExportType(BULK_EDIT_UPDATE); - return updateResult; - } catch (Exception e) { - var msg = String.format("Failed to read %s item records file for job id %s, reason: %s", outputFileName, jobCommand.getId(), e.getMessage()); - log.error(msg); - throw new FileOperationException(msg); - } - } - - private void saveResultToFile(List itemFormats, JobCommand jobCommand, String outputFileName, String propertyValue) { - try { - CsvHelper.saveRecordsToStorage(localFilesStorage, itemFormats, ItemFormat.class, outputFileName); - log.info("Saved {}", outputFileName); - jobCommand.setJobParameters(new JobParametersBuilder(jobCommand.getJobParameters()) - .addString(propertyValue, outputFileName) - .toJobParameters()); - } catch (Exception e) { - var msg = String.format("Failed to write %s item records file for job id %s, reason: %s", outputFileName, jobCommand.getId(), e.getMessage()); - log.error(msg); - throw new FileOperationException(msg); - } - } - - private ContentUpdateRecords applyContentUpdates(List itemFormats, ItemContentUpdateCollection contentUpdates, JobCommand jobCommand) { - var result = new ContentUpdateRecords(); - var errorStringBuilder = new StringBuilder(); - for (ItemFormat itemFormat: itemFormats) { - var updatedItemFormat = itemFormat; - var errorMessage = new ErrorMessage(); - - for (ItemContentUpdate contentUpdate: contentUpdates.getItemContentUpdates()) { - updatedItemFormat = applyContentUpdate(updatedItemFormat, contentUpdate, errorMessage); - } - - if (!Objects.equals(itemFormat, updatedItemFormat)) { - if (isLocationChange(contentUpdates)) { - updateEffectiveLocation(updatedItemFormat); - } - result.addToUpdated(updatedItemFormat); - result.addToPreview(applyUpdatesForPreview(contentUpdates, updatedItemFormat)); - } else { - var previewItemFormat = applyUpdatesForPreview(contentUpdates, itemFormat); - result.addToPreview(previewItemFormat); - if (Objects.equals(itemFormat, previewItemFormat)) { - errorMessage.setValue(NO_CHANGE_MESSAGE); - } - } - - if (errorMessage.getValue() != null) { - errorStringBuilder - .append(itemFormat.getIdentifier(jobCommand.getJobParameters().getString(IDENTIFIER_TYPE))) - .append(COMMA) - .append(errorMessage.getValue()) - .append(System.lineSeparator()); - } - } - if (!errorStringBuilder.toString().isEmpty()) { - errorsService.saveErrorInCSV(jobCommand.getId().toString(), errorStringBuilder.toString(), FilenameUtils.getName(jobCommand.getJobParameters().getString(FILE_NAME))); - } - return result; - } - - - private ItemFormat applyContentUpdate(ItemFormat itemFormat, ItemContentUpdate contentUpdate, ErrorMessage errorMessage) { - if (REPLACE_WITH == contentUpdate.getAction()) { - return applyReplaceWith(itemFormat, contentUpdate, errorMessage); - } else if (CLEAR_FIELD == contentUpdate.getAction()) { - if (STATUS == contentUpdate.getOption()) { - errorMessage.setValue(STATUS_FIELD_CAN_NOT_CLEARED); - } else if (PERMANENT_LOAN_TYPE == contentUpdate.getOption()) { - errorMessage.setValue("Permanent loan type cannot be cleared"); - } else { - return applyClearField(itemFormat, contentUpdate); - } - } - return itemFormat; - } - - private ItemFormat applyReplaceWith(ItemFormat itemFormat, ItemContentUpdate contentUpdate, ErrorMessage errorMessage) { - var newValue = isEmpty(contentUpdate.getValue()) ? EMPTY : contentUpdate.getValue().toString(); - switch (contentUpdate.getOption()) { - case PERMANENT_LOAN_TYPE: - return replacePermanentLoanTypeIfAllowed(itemFormat, newValue, errorMessage); - case TEMPORARY_LOAN_TYPE: - return itemFormat.withTemporaryLoanType(newValue); - case TEMPORARY_LOCATION: - return itemFormat.withTemporaryLocation(newValue); - case PERMANENT_LOCATION: - return itemFormat.withPermanentLocation(newValue); - case STATUS: - return replaceStatusIfAllowed(itemFormat, newValue, errorMessage); - default: - return itemFormat; - } - } - - private ItemFormat replacePermanentLoanTypeIfAllowed(ItemFormat itemFormat, String newValue, ErrorMessage errorMessage) { - if (newValue.isEmpty()) { - errorMessage.setValue("Permanent loan type value cannot be empty"); - return itemFormat; - } else { - return itemFormat.withPermanentLoanType(newValue); - } - } - - private ItemFormat applyClearField(ItemFormat itemFormat, ItemContentUpdate contentUpdate) { - switch (contentUpdate.getOption()) { - case PERMANENT_LOCATION: - return itemFormat.withPermanentLocation(EMPTY); - case TEMPORARY_LOCATION: - return itemFormat.withTemporaryLocation(EMPTY); - case TEMPORARY_LOAN_TYPE: - return itemFormat.withTemporaryLoanType(EMPTY); - default: - return itemFormat; - } - } - - private void updateEffectiveLocation(ItemFormat itemFormat) { - if (isEmpty(itemFormat.getTemporaryLocation())) { - itemFormat.setEffectiveLocation(isEmpty(itemFormat.getPermanentLocation()) ? - itemReferenceService.getHoldingEffectiveLocationCodeById(itemFormat.getHoldingsRecordId()) : - itemFormat.getPermanentLocation()); - } else { - itemFormat.setEffectiveLocation(itemFormat.getTemporaryLocation()); - } - } - - private boolean isLocationChange(ItemContentUpdateCollection contentUpdates) { - return contentUpdates.getItemContentUpdates().stream() - .anyMatch(update -> TEMPORARY_LOCATION == update.getOption() || PERMANENT_LOCATION == update.getOption()); - } - - private ItemFormat replaceStatusIfAllowed(ItemFormat itemFormat, String newStatus, ErrorMessage errorMessage) { - var currentStatus = extractStatusName(itemFormat.getStatus()); - if (!currentStatus.equals(newStatus)) { - if (itemReferenceService.getAllowedStatuses(currentStatus).contains(newStatus)) { - return itemFormat.withStatus(String.join(ARRAY_DELIMITER, newStatus, dateToString(Date.from(LocalDateTime.now().atZone(UTC).toInstant())))); - } else { - var msg = String.format(STATUS_VALUE_NOT_ALLOWED, newStatus); - errorMessage.setValue(msg); - } - } - return itemFormat; - } - - private String extractStatusName(String s) { - var tokens = s.split(ARRAY_DELIMITER, -1); - return tokens.length > 0 ? tokens[0] : EMPTY; - } - - private ItemFormat applyUpdatesForPreview(ItemContentUpdateCollection contentUpdates, ItemFormat itemFormat) { - var updatedItemFormat = applyStatusUpdateForPreview(contentUpdates, itemFormat); - return applyLoanTypeUpdateForPreview(contentUpdates, updatedItemFormat); - } - - private ItemFormat applyStatusUpdateForPreview(ItemContentUpdateCollection contentUpdates, ItemFormat itemFormat) { - var statusUpdate = contentUpdates.getItemContentUpdates().stream() - .filter(contentUpdate -> contentUpdate.getOption() == STATUS) - .findFirst(); - if (statusUpdate.isPresent() && nonNull(statusUpdate.get().getValue()) && !extractStatusName(itemFormat.getStatus()).equals(statusUpdate.get().getValue())) { - return itemFormat.withStatus(String.join(ARRAY_DELIMITER, statusUpdate.get().getValue().toString(), dateToString(Date.from(LocalDateTime.now().atZone(UTC).toInstant())))); - } - return itemFormat; - } - - private ItemFormat applyLoanTypeUpdateForPreview(ItemContentUpdateCollection contentUpdates, ItemFormat itemFormat) { - var update = contentUpdates.getItemContentUpdates().stream() - .filter(contentUpdate -> contentUpdate.getOption() == PERMANENT_LOAN_TYPE) - .findFirst(); - if (update.isPresent() && !Objects.equals(update.get().getValue(), itemFormat.getPermanentLoanType())) { - return itemFormat.withPermanentLoanType(isNull(update.get().getValue()) ? EMPTY : update.get().getValue().toString()); - } - return itemFormat; - } -} diff --git a/src/main/java/org/folio/dew/service/BulkEditParseService.java b/src/main/java/org/folio/dew/service/BulkEditParseService.java deleted file mode 100644 index e62953fc2..000000000 --- a/src/main/java/org/folio/dew/service/BulkEditParseService.java +++ /dev/null @@ -1,445 +0,0 @@ -package org.folio.dew.service; - -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isEmpty; -import static org.apache.commons.lang3.StringUtils.isNotEmpty; -import static org.folio.dew.utils.BulkEditProcessorHelper.dateFromString; -import static org.folio.dew.utils.Constants.ARRAY_DELIMITER; -import static org.folio.dew.utils.Constants.ITEM_DELIMITER_PATTERN; -import static org.folio.dew.utils.Constants.KEY_VALUE_DELIMITER; -import static org.folio.dew.utils.Constants.LINE_BREAK; -import static org.folio.dew.utils.Constants.LINE_BREAK_REPLACEMENT; - -import java.net.URI; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -import lombok.extern.log4j.Log4j2; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; -import org.folio.dew.domain.dto.Address; -import org.folio.dew.domain.dto.CirculationNote; -import org.folio.dew.domain.dto.ContributorName; -import org.folio.dew.domain.dto.CustomField; - -import org.folio.dew.domain.dto.InventoryItemStatus; -import org.folio.dew.domain.dto.Item; -import org.folio.dew.domain.dto.ItemFormat; -import org.folio.dew.domain.dto.ItemLocation; -import org.folio.dew.domain.dto.ItemNote; -import org.folio.dew.domain.dto.LastCheckIn; -import org.folio.dew.domain.dto.LoanType; -import org.folio.dew.domain.dto.MaterialType; -import org.folio.dew.domain.dto.Personal; -import org.folio.dew.domain.dto.Source; -import org.folio.dew.domain.dto.Tags; -import org.folio.dew.domain.dto.User; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.error.BulkEditException; -import org.springframework.stereotype.Component; - -import lombok.RequiredArgsConstructor; - -@Component -@RequiredArgsConstructor -@Log4j2 -public class BulkEditParseService { - - private final UserReferenceService userReferenceService; - private final ItemReferenceService itemReferenceService; - - private final ElectronicAccessService electronicAccessService; - private final SpecialCharacterEscaper escaper; - - private static final int ADDRESS_ID = 0; - private static final int ADDRESS_COUNTRY_ID = 1; - private static final int ADDRESS_LINE_1 = 2; - private static final int ADDRESS_LINE_2 = 3; - private static final int ADDRESS_CITY = 4; - private static final int ADDRESS_REGION = 5; - private static final int ADDRESS_POSTAL_CODE = 6; - private static final int ADDRESS_PRIMARY_ADDRESS = 7; - private static final int ADDRESS_TYPE = 8; - private static final int NUMBER_OF_ITEM_NOTE_COMPONENTS = 3; - private static final int NOTE_TYPE_NAME_INDEX = 0; - private static final int NOTE_INDEX = 1; - private static final int STAFF_ONLY_OFFSET = 1; - - private static final int NUMBER_OF_CIRCULATION_NOTE_COMPONENTS = 8; - private static final int CIRC_NOTE_ID_INDEX = 0; - private static final int CIRC_NOTE_TYPE_INDEX = 1; - private static final int CIRC_NOTE_NOTE_INDEX = 2; - private static final int CIRC_NOTE_STAFF_ONLY_OFFSET = 5; - private static final int CIRC_NOTE_SOURCE_ID_OFFSET = 4; - private static final int CIRC_NOTE_LAST_NAME_OFFSET = 3; - private static final int CIRC_NOTE_FIRST_NAME_OFFSET = 2; - private static final int CIRC_NOTE_DATE_OFFSET = 1; - - private static final int NUMBER_OF_STATUS_COMPONENTS = 2; - private static final int STATUS_NAME_INDEX = 0; - private static final int STATUS_DATE_INDEX = 1; - private static final int NUMBER_OF_LAST_CHECK_IN_COMPONENTS = 3; - private static final int LAST_CHECK_IN_SERVICE_POINT_NAME_INDEX = 0; - private static final int LAST_CHECK_IN_USERNAME_INDEX = 1; - private static final int LAST_CHECK_IN_DATE_TIME_INDEX = 2; - - private static final String START_ARRAY = "["; - private static final String END_ARRAY = "]"; - - public User mapUserFormatToUser(UserFormat userFormat) { - User user = new User(); - populateUserFields(user, userFormat); - return user; - } - - private void populateUserFields(User user, UserFormat userFormat) { - user.setId(userFormat.getId()); - user.setUsername(isEmpty(userFormat.getUsername()) ? null : userFormat.getUsername()); - user.setExternalSystemId(isBlank(userFormat.getExternalSystemId()) ? null : userFormat.getExternalSystemId()); - user.setBarcode(isBlank(userFormat.getBarcode()) ? null : userFormat.getBarcode()); - user.setActive(getIsActive(userFormat)); - user.setType(userFormat.getType()); - user.setPatronGroup(userReferenceService.getPatronGroupIdByName(userFormat.getPatronGroup())); - user.setDepartments(new HashSet<>(getUserDepartments(userFormat))); - user.setProxyFor(isEmpty(userFormat.getProxyFor()) ? Collections.emptyList() : Arrays.asList(userFormat.getProxyFor().split(ARRAY_DELIMITER))); - user.setPersonal(getUserPersonalInfo(userFormat)); - user.setEnrollmentDate(dateFromString(userFormat.getEnrollmentDate())); - user.setExpirationDate(dateFromString(userFormat.getExpirationDate())); - user.setTags(getTags(userFormat)); - user.setCustomFields(getCustomFields(userFormat)); - user.setPreferredEmailCommunication(getPreferredEmailCommunication(userFormat)); - } - - private boolean getIsActive(UserFormat userFormat) { - String value = userFormat.getActive(); - if (value.matches("true") || value.matches("false")) { - return Boolean.parseBoolean(value); - } - //TODO in MODBULKED-14 save error that filed has a wrong value instead of returning false - return false; - } - - private List getUserDepartments(UserFormat userFormat) { - String[] departmentNames = userFormat.getDepartments().split(ARRAY_DELIMITER); - if (departmentNames.length > 0) { - return Arrays.stream(departmentNames).parallel() - .filter(StringUtils::isNotEmpty) - .map(escaper::restore) - .map(userReferenceService::getDepartmentIdByName) - .map(UUID::fromString) - .collect(Collectors.toList()); - } - return Collections.emptyList(); - } - - private Personal getUserPersonalInfo(UserFormat userFormat) { - Personal personal = new Personal(); - personal.setLastName(userFormat.getLastName()); - personal.setFirstName(userFormat.getFirstName()); - personal.setMiddleName(userFormat.getMiddleName()); - personal.setPreferredFirstName(userFormat.getPreferredFirstName()); - personal.setEmail(userFormat.getEmail()); - personal.setPhone(userFormat.getPhone()); - personal.setMobilePhone(userFormat.getMobilePhone()); - personal.setDateOfBirth(dateFromString(userFormat.getDateOfBirth())); - personal.setAddresses(getUserAddresses(userFormat)); - personal.setPreferredContactTypeId(isEmpty(userFormat.getPreferredContactTypeId()) ? null : userFormat.getPreferredContactTypeId()); - personal.setProfilePictureLink(isEmpty(userFormat.getProfilePictureLink()) ? null : URI.create(userFormat.getProfilePictureLink())); - return personal; - } - - private List
getUserAddresses(UserFormat userFormat) { - String[] addresses = userFormat.getAddresses().split(ITEM_DELIMITER_PATTERN); - if (addresses.length > 0) { - return Arrays.stream(addresses) - .parallel() - .filter(StringUtils::isNotEmpty) - .map(this::getAddressFromString) - .collect(Collectors.toList()); - } - return Collections.emptyList(); - } - - private Address getAddressFromString(String stringAddress) { - Address address = new Address(); - List addressFields = escaper.restore(Arrays.asList(stringAddress.split(ARRAY_DELIMITER))); - address.setId(addressFields.get(ADDRESS_ID)); - address.setCountryId(addressFields.get(ADDRESS_COUNTRY_ID)); - address.setAddressLine1(addressFields.get(ADDRESS_LINE_1)); - address.setAddressLine2(addressFields.get(ADDRESS_LINE_2)); - address.setCity(addressFields.get(ADDRESS_CITY)); - address.setRegion(addressFields.get(ADDRESS_REGION)); - address.setPostalCode(addressFields.get(ADDRESS_POSTAL_CODE)); - address.setPrimaryAddress(Boolean.valueOf(addressFields.get(ADDRESS_PRIMARY_ADDRESS))); - address.setAddressTypeId(userReferenceService.getAddressTypeIdByDesc(addressFields.get(ADDRESS_TYPE))); - return address; - } - - private Tags getTags(UserFormat userFormat) { - if (isNotEmpty(userFormat.getTags())) { - Tags tags = new Tags(); - List tagList = escaper.restore(Arrays.asList(userFormat.getTags().split(ARRAY_DELIMITER))); - return tags.tagList(tagList); - } - return null; - } - - private Map getCustomFields(UserFormat userFormat) { - if (isNotEmpty(userFormat.getCustomFields())) { - return Arrays.stream(userFormat.getCustomFields().split(ITEM_DELIMITER_PATTERN)) - .map(this::restoreCustomFieldValue) - .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); - } - return Collections.emptyMap(); - } - - private Set getPreferredEmailCommunication(UserFormat userFormat) { - if (isNotEmpty(userFormat.getPreferredEmailCommunication())) { - return Arrays.stream(userFormat.getPreferredEmailCommunication().split(ARRAY_DELIMITER)) - .map(User.PreferredEmailCommunicationEnum::fromValue) - .collect(Collectors.toSet()); - } - return Collections.emptySet(); - } - - private Pair restoreCustomFieldValue(String s) { - var valuePair = stringToPair(s); - var fieldName = valuePair.getKey(); - var fieldValue = valuePair.getValue(); - var customField = userReferenceService.getCustomFieldByName(fieldName); - switch (customField.getType()) { - case DATE_PICKER: - return Pair.of(customField.getRefId(), fieldValue); - case SINGLE_CHECKBOX: - return Pair.of(customField.getRefId(), Boolean.parseBoolean(fieldValue)); - case TEXTBOX_LONG: - case TEXTBOX_SHORT: - return Pair.of(customField.getRefId(), fieldValue.replace(LINE_BREAK_REPLACEMENT, LINE_BREAK)); - case SINGLE_SELECT_DROPDOWN: - case RADIO_BUTTON: - return Pair.of(customField.getRefId(), restoreValueId(customField, fieldValue)); - case MULTI_SELECT_DROPDOWN: - return Pair.of(customField.getRefId(), restoreValueIds(customField, fieldValue)); - default: - throw new BulkEditException("Invalid custom field: " + s); - } - } - - private Pair stringToPair(String value) { - var tokens = value.split(KEY_VALUE_DELIMITER, -1); - if (tokens.length == 2) { - return Pair.of(escaper.restore(tokens[0]), escaper.restore(tokens[1])); - } else { - var msg = "Invalid key/value pair: " + value; - log.error(msg); - throw new BulkEditException(msg); - } - } - - private List restoreValueIds(CustomField customField, String values) { - return isEmpty(values) ? - Collections.emptyList() : - Arrays.stream(values.split(ARRAY_DELIMITER)) - .map(token -> restoreValueId(customField, token)) - .collect(Collectors.toList()); - } - - private String restoreValueId(CustomField customField, String value) { - var optionalValue = customField.getSelectField().getOptions().getValues().stream() - .filter(selectFieldOption -> Objects.equals(value, selectFieldOption.getValue())) - .findFirst(); - if (optionalValue.isPresent()) { - return optionalValue.get().getId(); - } else { - var msg = "Invalid custom field value: " + value; - log.error(msg); - throw new BulkEditException(msg); - } - } - - public Item mapItemFormatToItem(ItemFormat itemFormat) { - return new Item() - .id(itemFormat.getId()) - .hrid(itemFormat.getHrid()) - .holdingsRecordId(itemFormat.getHoldingsRecordId()) - .formerIds(restoreListValue(itemFormat.getFormerIds())) - .discoverySuppress(isEmpty(itemFormat.getDiscoverySuppress()) ? null : Boolean.valueOf(itemFormat.getDiscoverySuppress())) - .title(itemFormat.getTitle()) - .barcode(restoreStringValue(itemFormat.getBarcode())) - .effectiveShelvingOrder(restoreStringValue(itemFormat.getEffectiveShelvingOrder())) - .accessionNumber(restoreStringValue(itemFormat.getAccessionNumber())) - .itemLevelCallNumber(restoreStringValue(itemFormat.getItemLevelCallNumber())) - .itemLevelCallNumberPrefix(restoreStringValue(itemFormat.getItemLevelCallNumberPrefix())) - .itemLevelCallNumberSuffix(restoreStringValue(itemFormat.getItemLevelCallNumberSuffix())) - .itemLevelCallNumberTypeId(restoreItemLevelCallNumberTypeId(itemFormat.getItemLevelCallNumberType())) - .volume(restoreStringValue(itemFormat.getVolume())) - .enumeration(restoreStringValue(itemFormat.getEnumeration())) - .chronology(restoreStringValue(itemFormat.getChronology())) - .yearCaption(restoreListValue(itemFormat.getYearCaption())) - .itemIdentifier(restoreStringValue(itemFormat.getItemIdentifier())) - .copyNumber(restoreStringValue(itemFormat.getCopyNumber())) - .numberOfPieces(restoreStringValue(itemFormat.getNumberOfPieces())) - .descriptionOfPieces(restoreStringValue(itemFormat.getDescriptionOfPieces())) - .numberOfMissingPieces(restoreStringValue(itemFormat.getNumberOfMissingPieces())) - .missingPieces(restoreStringValue(itemFormat.getMissingPieces())) - .missingPiecesDate(restoreStringValue(itemFormat.getMissingPiecesDate())) - .itemDamagedStatusId(restoreItemDamagedStatusId(itemFormat.getItemDamagedStatus())) - .itemDamagedStatusDate(restoreStringValue(itemFormat.getItemDamagedStatusDate())) - .administrativeNotes(restoreListValue(itemFormat.getAdministrativeNotes())) - .notes(restoreItemNotes(itemFormat.getNotes())) - .circulationNotes(restoreCirculationNotes(itemFormat.getCheckInNotes() + ITEM_DELIMITER_PATTERN + itemFormat.getCheckOutNotes())) - .status(restoreStatus(itemFormat.getStatus())) - .materialType(restoreMaterialType(itemFormat.getMaterialType())) - .permanentLoanType(restoreLoanType(itemFormat.getPermanentLoanType())) - .temporaryLoanType(restoreLoanType(itemFormat.getTemporaryLoanType())) - .permanentLocation(restoreLocation(itemFormat.getPermanentLocation())) - .temporaryLocation(restoreLocation(itemFormat.getTemporaryLocation())) - .effectiveLocation(restoreLocation(itemFormat.getEffectiveLocation())) - .electronicAccess(electronicAccessService.restoreElectronicAccess(itemFormat.getElectronicAccess())) - .statisticalCodeIds(restoreStatisticalCodeIds(itemFormat.getStatisticalCodes())) - .tags(isEmpty(itemFormat.getTags()) ? new Tags().tagList(Collections.emptyList()) : new Tags().tagList(restoreListValue(itemFormat.getTags()))); - } - - private String restoreStringValue(String s) { - return isEmpty(s) || "null".equalsIgnoreCase(s) ? null : s; - } - - private List restoreListValue(String s) { - return isEmpty(s) ? - Collections.emptyList() : - escaper.restore(Arrays.asList(s.split(ARRAY_DELIMITER))); - } - - private List restoreContributorNames(String s) { - return isEmpty(s) ? - Collections.emptyList() : - Arrays.stream(s.split(ARRAY_DELIMITER)) - .map(escaper::restore) - .map(token -> new ContributorName().name(token)) - .collect(Collectors.toList()); - } - - private String restoreItemLevelCallNumberTypeId(String name) { - return itemReferenceService.getCallNumberTypeIdByName(name); - } - - private String restoreItemDamagedStatusId(String name) { - return itemReferenceService.getDamagedStatusIdByName(name); - } - - private List restoreItemNotes(String s) { - return isEmpty(s) ? Collections.emptyList() : - Arrays.stream(s.split(ITEM_DELIMITER_PATTERN)) - .map(this::restoreItemNote) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private ItemNote restoreItemNote(String s) { - if (isNotEmpty(s)) { - var tokens = s.split(ARRAY_DELIMITER, -1); - if (tokens.length < NUMBER_OF_ITEM_NOTE_COMPONENTS) { - throw new BulkEditException(String.format("Illegal number of item note elements: %d, expected: %d", tokens.length, NUMBER_OF_ITEM_NOTE_COMPONENTS)); - } - - return new ItemNote() - .itemNoteTypeId(itemReferenceService.getNoteTypeIdByName(escaper.restore(tokens[NOTE_TYPE_NAME_INDEX]))) - .note(Arrays.stream(tokens, NOTE_INDEX, tokens.length - STAFF_ONLY_OFFSET) - .map(escaper::restore) - .collect(Collectors.joining(";"))) - .staffOnly(Boolean.valueOf(tokens[tokens.length - STAFF_ONLY_OFFSET])); - - } - return null; - } - - private List restoreCirculationNotes(String s) { - return isEmpty(s) ? Collections.emptyList() : - Arrays.stream(s.split(ITEM_DELIMITER_PATTERN)) - .map(this::restoreCirculationNote) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private CirculationNote restoreCirculationNote(String s) { - if (isNotEmpty(s)) { - var tokens = s.split(ARRAY_DELIMITER, -1); - if (tokens.length < NUMBER_OF_CIRCULATION_NOTE_COMPONENTS) { - throw new BulkEditException(String.format("Illegal number of circulation note elements: %d, expected: %d", tokens.length, NUMBER_OF_CIRCULATION_NOTE_COMPONENTS)); - } - return new CirculationNote() - .id(tokens[CIRC_NOTE_ID_INDEX]) - .noteType(CirculationNote.NoteTypeEnum.fromValue(tokens[CIRC_NOTE_TYPE_INDEX])) - .note(Arrays.stream(tokens, CIRC_NOTE_NOTE_INDEX, tokens.length - CIRC_NOTE_STAFF_ONLY_OFFSET) - .map(escaper::restore) - .collect(Collectors.joining(";"))) - .staffOnly(Boolean.valueOf(tokens[tokens.length - CIRC_NOTE_STAFF_ONLY_OFFSET])) - .source(new Source() - .id(tokens[tokens.length - CIRC_NOTE_SOURCE_ID_OFFSET]) - .personal(new Personal() - .lastName(escaper.restore(tokens[tokens.length - CIRC_NOTE_LAST_NAME_OFFSET])) - .firstName(escaper.restore(tokens[tokens.length - CIRC_NOTE_FIRST_NAME_OFFSET])))) - .date(dateFromString(tokens[tokens.length - CIRC_NOTE_DATE_OFFSET])); - } - return null; - } - - private InventoryItemStatus restoreStatus(String s) { - if (isNotEmpty(s)) { - var tokens = s.split(ARRAY_DELIMITER, -1); - if (NUMBER_OF_STATUS_COMPONENTS == tokens.length) { - return new InventoryItemStatus() - .name(InventoryItemStatus.NameEnum.fromValue(tokens[STATUS_NAME_INDEX])) - .date(dateFromString(tokens[STATUS_DATE_INDEX])); - } - throw new BulkEditException(String.format("Illegal number of item status elements: %d, expected: %d", tokens.length, NUMBER_OF_STATUS_COMPONENTS)); - } - return null; - } - - private MaterialType restoreMaterialType(String s) { - return isEmpty(s) ? null : itemReferenceService.getMaterialTypeByName(s); - } - - private LoanType restoreLoanType(String s) { - return isEmpty(s) ? null : itemReferenceService.getLoanTypeByName(s); - } - - private ItemLocation restoreLocation(String s) { - return isEmpty(s) ? null : itemReferenceService.getLocationByName(s); - } - - private String restoreServicePointId(String s) { - return itemReferenceService.getServicePointIdByName(s); - } - - private List restoreStatisticalCodeIds(String s) { - return isEmpty(s) ? Collections.emptyList() : - Arrays.stream(s.split(ARRAY_DELIMITER)) - .map(escaper::restore) - .map(itemReferenceService::getStatisticalCodeIdByCode) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private LastCheckIn restoreLastCheckIn(String s) { - if (isNotEmpty(s)) { - var tokens = s.split(ARRAY_DELIMITER, -1); - if (NUMBER_OF_LAST_CHECK_IN_COMPONENTS == tokens.length) { - return new LastCheckIn() - .servicePointId(itemReferenceService.getServicePointIdByName(escaper.restore(tokens[LAST_CHECK_IN_SERVICE_POINT_NAME_INDEX]))) - .staffMemberId(itemReferenceService.getUserIdByUserName(escaper.restore(tokens[LAST_CHECK_IN_USERNAME_INDEX]))) - .dateTime(restoreStringValue(tokens[LAST_CHECK_IN_DATE_TIME_INDEX])); - } - throw new BulkEditException(String.format("Illegal number of last check in elements: %d, expected: %d", tokens.length, NUMBER_OF_LAST_CHECK_IN_COMPONENTS)); - } - return null; - } -} diff --git a/src/main/java/org/folio/dew/service/BulkEditRollBackJobLauncher.java b/src/main/java/org/folio/dew/service/BulkEditRollBackJobLauncher.java deleted file mode 100644 index 0b7f76a32..000000000 --- a/src/main/java/org/folio/dew/service/BulkEditRollBackJobLauncher.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.folio.dew.service; - -import org.springframework.batch.core.Job; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.JobParametersInvalidException; -import org.springframework.batch.core.launch.support.SimpleJobLauncher; -import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; -import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.repository.JobRestartException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; - -@Component -public class BulkEditRollBackJobLauncher extends SimpleJobLauncher { - - @Autowired - public BulkEditRollBackJobLauncher(JobRepository jobRepository) { - this.setJobRepository(jobRepository); - } - - @Override - @Transactional(propagation = Propagation.NOT_SUPPORTED) - public JobExecution run(Job job, JobParameters jobParameters) throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException { - return super.run(job, jobParameters); - } -} diff --git a/src/main/java/org/folio/dew/service/BulkEditRollBackService.java b/src/main/java/org/folio/dew/service/BulkEditRollBackService.java deleted file mode 100644 index c3c557fcc..000000000 --- a/src/main/java/org/folio/dew/service/BulkEditRollBackService.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.folio.dew.service; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.lang3.StringUtils; -import org.folio.dew.client.DataExportSpringClient; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.utils.Constants; -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.batch.core.launch.JobOperator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -import static org.folio.dew.utils.Constants.JOB_ID_SEPARATOR; -import static org.folio.dew.utils.Constants.PATH_SEPARATOR; -import static org.folio.dew.utils.Constants.TMP_DIR_PROPERTY; - -@Service -@RequiredArgsConstructor -@Log4j2 -public class BulkEditRollBackService { - - private static final String ROLLBACK_ERROR_MESSAGE = "Rollback error"; - private static final String ROLLBACK_DONE_MESSAGE = "Rollback has been done"; - - private final Map executionIdPerJobId = new ConcurrentHashMap<>(); - private final Map> usersIdsToRollBackForJobId = new ConcurrentHashMap<>(); - - private String workDir; - @Value("${spring.application.name}") - private String springApplicationName; - private final JobOperator jobOperator; - @Autowired - @Qualifier("bulkEditRollBackJob") - private Job job; - private final BulkEditRollBackJobLauncher rollBackJobLauncher; - private final DataExportSpringClient dataExportSpringClient; - private final RemoteFilesStorage remoteFilesStorage; - - @PostConstruct - public void postConstruct() { - workDir = System.getProperty(TMP_DIR_PROPERTY) + PATH_SEPARATOR + springApplicationName + PATH_SEPARATOR; - } - - public String stopAndRollBackJobExecutionByJobId(UUID jobId) { - try { - log.info("Rollback for jobId {} is started", jobId.toString()); - if (executionIdPerJobId.containsKey(jobId)) { - jobOperator.stop(executionIdPerJobId.get(jobId)); - } - rollBackByJobId(jobId); - return ROLLBACK_DONE_MESSAGE; - } catch (Exception e) { - log.error(e.getMessage()); - } - return ROLLBACK_ERROR_MESSAGE; - } - - public void putExecutionInfoPerJob(long executionId, UUID jobId) { - executionIdPerJobId.put(jobId, executionId); - } - - public void putUserIdForJob(String userId, UUID jobId) { - var existUsersIds = usersIdsToRollBackForJobId.computeIfAbsent(jobId, key -> new HashSet<>()); - existUsersIds.add(userId); - } - - public boolean isUserBeRollBack(String userId, UUID jobId) { - return !executionIdPerJobId.containsKey(jobId) || (usersIdsToRollBackForJobId.get(jobId) != null - && usersIdsToRollBackForJobId.get(jobId).remove(userId)); - } - - public boolean isExecutionIdExistForJob(UUID jobId) { - return executionIdPerJobId.containsKey(jobId); - } - public void cleanJobData(String exitCode, UUID jobId) { - if (!ExitStatus.STOPPED.getExitCode().equals(exitCode)) { - executionIdPerJobId.remove(jobId); - usersIdsToRollBackForJobId.remove(jobId); - } - } - - public void cleanJobData(UUID jobId) { - executionIdPerJobId.remove(jobId); - usersIdsToRollBackForJobId.remove(jobId); - } - - @SneakyThrows - public String getFileForRollBackFromMinIO(String fileUploadName) { - var jobId = getJobIdFromFileName(fileUploadName); - var files = dataExportSpringClient.getJobById(jobId).getFiles(); - if (files.isEmpty()) { - var error = "Rollback file does not exist for job " + jobId; - throw new BulkEditException(error); - } - return files.get(0); - } - - private String getJobIdFromFileName(String fileUploadName) { - return StringUtils.substringBefore(fileUploadName, JOB_ID_SEPARATOR); - } - - @SneakyThrows - private void rollBackByJobId(UUID jobId) { - var fileForRollBack = workDir + jobId.toString() + "_rollBack.csv"; - var files = dataExportSpringClient.getJobById(jobId.toString()).getFiles(); - if (files.isEmpty()) { - var error = "Rollback file does not exist for job " + jobId.toString(); - throw new BulkEditException(error); - } - var fileForRollBackMinIOPath = files.get(0); - var objectName = getObjectName(fileForRollBackMinIOPath); - remoteFilesStorage.downloadObject(objectName, fileForRollBack); - rollBackJobLauncher.run(job, getRollBackParameters(jobId.toString(), fileForRollBack)); - } - - private JobParameters getRollBackParameters(String jobId, String fileToRollBack) { - var jobParametersBuilder = new JobParametersBuilder(); - jobParametersBuilder.addString(Constants.JOB_ID, jobId); - jobParametersBuilder.addString(Constants.FILE_NAME, fileToRollBack); - return jobParametersBuilder.toJobParameters(); - } - - private String getObjectName(String path) { - String[] splitted = path.split("/"); - return StringUtils.substringBeforeLast(splitted[splitted.length - 1], ".csv") + ".csv"; - } -} diff --git a/src/main/java/org/folio/dew/service/ContentUpdateRecords.java b/src/main/java/org/folio/dew/service/ContentUpdateRecords.java deleted file mode 100644 index 47493629b..000000000 --- a/src/main/java/org/folio/dew/service/ContentUpdateRecords.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.folio.dew.service; - -import lombok.Getter; - -import java.util.ArrayList; -import java.util.List; - -@Getter -public class ContentUpdateRecords { - - private List updated = new ArrayList<>(); - private List preview = new ArrayList<>(); - - public void addToUpdated(T entity) { - updated.add(entity); - } - - public void addToPreview(T entity) { - preview.add(entity); - } -} diff --git a/src/main/java/org/folio/dew/service/HoldingsReferenceService.java b/src/main/java/org/folio/dew/service/HoldingsReferenceService.java index eb8be4373..2f0e39189 100644 --- a/src/main/java/org/folio/dew/service/HoldingsReferenceService.java +++ b/src/main/java/org/folio/dew/service/HoldingsReferenceService.java @@ -22,7 +22,6 @@ import org.folio.dew.client.StatisticalCodeClient; import org.folio.dew.domain.dto.ErrorServiceArgs; import org.folio.dew.domain.dto.HoldingsRecord; -import org.folio.dew.domain.dto.ItemLocation; import org.folio.dew.error.BulkEditException; import org.folio.dew.error.NotFoundException; import org.folio.spring.FolioExecutionContext; @@ -137,17 +136,6 @@ public String getLocationNameById(String id, String tenantId) { } } - @Cacheable(cacheNames = "holdingsLocations") - public ItemLocation getLocationByName(String name) { - var locations = locationClient.getLocationByQuery(String.format(QUERY_PATTERN_NAME, name)); - if (locations.getLocations().isEmpty()) { - var msg = "Location not found by name=" + name; - log.error(msg); - throw new BulkEditException(msg); - } - return locations.getLocations().get(0); - } - @Cacheable(cacheNames = "holdingsCallNumberTypesNames") public String getCallNumberTypeNameById(String id, ErrorServiceArgs args, String tenantId) { try (var context = new FolioExecutionContextSetter(refreshAndGetFolioExecutionContext(tenantId, folioExecutionContext))) { diff --git a/src/main/java/org/folio/dew/service/ItemReferenceService.java b/src/main/java/org/folio/dew/service/ItemReferenceService.java index de4866ea9..c930243bc 100644 --- a/src/main/java/org/folio/dew/service/ItemReferenceService.java +++ b/src/main/java/org/folio/dew/service/ItemReferenceService.java @@ -25,11 +25,8 @@ import org.folio.dew.client.StatisticalCodeClient; import org.folio.dew.client.UserClient; import org.folio.dew.domain.dto.ErrorServiceArgs; -import org.folio.dew.domain.dto.ItemLocation; import org.folio.dew.domain.dto.ItemLocationCollection; -import org.folio.dew.domain.dto.LoanType; import org.folio.dew.domain.dto.LoanTypeCollection; -import org.folio.dew.domain.dto.MaterialType; import org.folio.dew.domain.dto.MaterialTypeCollection; import org.folio.dew.error.BulkEditException; import org.folio.dew.error.ConfigurationException; @@ -48,16 +45,12 @@ @RequiredArgsConstructor public class ItemReferenceService extends FolioExecutionContextManager { private static final String QUERY_PATTERN_NAME = "name==\"%s\""; - private static final String QUERY_PATTERN_CODE = "code==\"%s\""; - private static final String QUERY_PATTERN_USERNAME = "username==\"%s\""; public static final String EFFECTIVE_LOCATION_ID = "effectiveLocationId"; private final CallNumberTypeClient callNumberTypeClient; private final DamagedStatusClient damagedStatusClient; private final ItemNoteTypeClient itemNoteTypeClient; - private final ServicePointClient servicePointClient; private final StatisticalCodeClient statisticalCodeClient; - private final UserClient userClient; private final LocationClient locationClient; private final MaterialTypeClient materialTypeClient; private final HoldingClient holdingClient; @@ -77,18 +70,6 @@ public String getCallNumberTypeNameById(String callNumberTypeId, ErrorServiceArg } } - @Cacheable(cacheNames = "callNumberTypeIds") - public String getCallNumberTypeIdByName(String name) { - if (isEmpty(name)) { - return null; - } - var response = callNumberTypeClient.getByQuery(String.format(QUERY_PATTERN_NAME, name)); - if (response.getCallNumberTypes().isEmpty()) { - return name; - } - return response.getCallNumberTypes().get(0).getId(); - } - @Cacheable(cacheNames = "damagedStatusNames") public String getDamagedStatusNameById(String damagedStatusId, ErrorServiceArgs args, String tenantId) { try (var context = new FolioExecutionContextSetter(refreshAndGetFolioExecutionContext(tenantId, folioExecutionContext))) { @@ -99,18 +80,6 @@ public String getDamagedStatusNameById(String damagedStatusId, ErrorServiceArgs } } - @Cacheable(cacheNames = "damagedStatusIds") - public String getDamagedStatusIdByName(String name) { - if (isEmpty(name)) { - return null; - } - var response = damagedStatusClient.getByQuery(String.format(QUERY_PATTERN_NAME, name)); - if (response.getItemDamageStatuses().isEmpty()) { - return name; - } - return response.getItemDamageStatuses().get(0).getId(); - } - @Cacheable(cacheNames = "noteTypeNames") public String getNoteTypeNameById(String noteTypeId, ErrorServiceArgs args, String tenantId) { try (var context = new FolioExecutionContextSetter(refreshAndGetFolioExecutionContext(tenantId, folioExecutionContext))) { @@ -121,30 +90,6 @@ public String getNoteTypeNameById(String noteTypeId, ErrorServiceArgs args, Stri } } - @Cacheable(cacheNames = "noteTypeIds") - public String getNoteTypeIdByName(String name) { - if (isEmpty(name)) { - return null; - } - var response = itemNoteTypeClient.getByQuery(String.format(QUERY_PATTERN_NAME, name)); - if (response.getItemNoteTypes().isEmpty()) { - return name; - } - return response.getItemNoteTypes().get(0).getId(); - } - - @Cacheable(cacheNames = "servicePointIds") - public String getServicePointIdByName(String name) { - if (isEmpty(name)) { - return null; - } - var response = servicePointClient.get(String.format(QUERY_PATTERN_NAME, name), 1L); - if (response.getServicepoints().isEmpty()) { - return name; - } - return response.getServicepoints().get(0).getId(); - } - @Cacheable(cacheNames = "statisticalCodeNames") public String getStatisticalCodeById(String statisticalCodeId, ErrorServiceArgs args, String tenantId) { try (var context = new FolioExecutionContextSetter(refreshAndGetFolioExecutionContext(tenantId, folioExecutionContext))) { @@ -155,69 +100,21 @@ public String getStatisticalCodeById(String statisticalCodeId, ErrorServiceArgs } } - @Cacheable(cacheNames = "statisticalCodeIds") - public String getStatisticalCodeIdByCode(String code) { - if (isEmpty(code)) { - return null; - } - var response = statisticalCodeClient.getByQuery(String.format(QUERY_PATTERN_CODE, code)); - if (response.getStatisticalCodes().isEmpty()) { - return code; - } - return response.getStatisticalCodes().get(0).getId(); - } - - @Cacheable(cacheNames = "userIds") - public String getUserIdByUserName(String name) { - if (isEmpty(name)) { - return null; - } - var response = userClient.getUserByQuery(String.format(QUERY_PATTERN_USERNAME, name)); - if (response.getUsers().isEmpty()) { - return name; - } - return response.getUsers().get(0).getId(); - } - @Cacheable(cacheNames = "locations") public ItemLocationCollection getItemLocationsByName(String name) { return locationClient.getLocationByQuery(String.format(QUERY_PATTERN_NAME, name)); } - public ItemLocation getLocationByName(String name) { - var locations = getItemLocationsByName(name); - if (locations.getLocations().isEmpty()) { - throw new BulkEditException("Location not found: " + name); - } - return locations.getLocations().get(0); - } - @Cacheable(cacheNames = "materialTypes") public MaterialTypeCollection getMaterialTypesByName(String name) { return materialTypeClient.getByQuery(String.format(QUERY_PATTERN_NAME, name)); } - public MaterialType getMaterialTypeByName(String name) { - var types = getMaterialTypesByName(name); - if (types.getMtypes().isEmpty()) { - throw new BulkEditException("Material type not found: " + name); - } - return types.getMtypes().get(0); - } - @Cacheable(cacheNames = "loanTypes") public LoanTypeCollection getLoanTypesByName(String name) { return loanTypeClient.getByQuery(String.format(QUERY_PATTERN_NAME, name)); } - public LoanType getLoanTypeByName(String name) { - var loanTypes = getLoanTypesByName(name); - if (loanTypes.getLoantypes().isEmpty()) { - throw new BulkEditException("Loan type not found: " + name); - } - return loanTypes.getLoantypes().get(0); - } - @Cacheable(cacheNames = "holdings") public String getHoldingEffectiveLocationCodeById(String id) { var holdingJson = holdingClient.getHoldingById(id); diff --git a/src/main/java/org/folio/dew/service/JobCommandsReceiverService.java b/src/main/java/org/folio/dew/service/JobCommandsReceiverService.java index 3d65c218e..fbc8fe0c1 100644 --- a/src/main/java/org/folio/dew/service/JobCommandsReceiverService.java +++ b/src/main/java/org/folio/dew/service/JobCommandsReceiverService.java @@ -3,7 +3,6 @@ import static java.util.Objects.nonNull; import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_IDENTIFIERS; import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_QUERY; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; import static org.folio.dew.domain.dto.ExportType.EDIFACT_ORDERS_EXPORT; import static org.folio.dew.utils.Constants.BULKEDIT_DIR_NAME; import static org.folio.dew.utils.Constants.CSV_EXTENSION; @@ -107,9 +106,9 @@ public void receiveStartJobCommand(@Payload JobCommand jobCommand, @Headers Map< prepareJobParameters(jobCommand); - if (Set.of(BULK_EDIT_IDENTIFIERS, BULK_EDIT_QUERY, BULK_EDIT_UPDATE).contains(jobCommand.getExportType())) { + if (Set.of(BULK_EDIT_IDENTIFIERS, BULK_EDIT_QUERY).contains(jobCommand.getExportType())) { addBulkEditJobCommand(jobCommand); - if (BULK_EDIT_IDENTIFIERS.equals(jobCommand.getExportType()) || BULK_EDIT_UPDATE.equals(jobCommand.getExportType())) { + if (BULK_EDIT_IDENTIFIERS.equals(jobCommand.getExportType())) { return; } } @@ -137,35 +136,6 @@ private String resolveJobKey(JobCommand jobCommand) { private void prepareJobParameters(JobCommand jobCommand) { var paramsBuilder = new JobParametersBuilder(jobCommand.getJobParameters()); - // TODO enrich exportType.json with value MARC_EXPORT - if ("MARC_EXPORT".equals(jobCommand.getExportType().getValue())) { - var uploadedFilePath = jobCommand.getJobParameters().getString(FILE_NAME); - if (nonNull(uploadedFilePath) && FilenameUtils.isExtension(uploadedFilePath, "cql")) { - var tempIdentifiersFileName = workDir + FilenameUtils.getBaseName(uploadedFilePath) + CSV_EXTENSION; - try (var lines = localFilesStorage.lines(uploadedFilePath); - var outputStream = new FileOutputStream(tempIdentifiersFileName)) { - var query = lines.collect(Collectors.joining()); - // TODO enrich entityType.json with values INSTANCE, HOLDINGS - InputStreamResource resource = null; - if ("INSTANCE".equals(jobCommand.getEntityType().getValue())) { - resource = searchClient.getInstanceIds(query).getBody(); - } else if ("HOLDINGS".equals(jobCommand.getEntityType().getValue())) { - resource = searchClient.getHoldingIds(query).getBody(); - } - if (nonNull(resource)) { - resource.getInputStream().transferTo(outputStream); - } - var identifiersUrl = remoteFilesStorage.objectToPresignedObjectUrl( - remoteFilesStorage.uploadObject(FilenameUtils.getName(tempIdentifiersFileName), tempIdentifiersFileName, null, "text/csv", true)); - paramsBuilder.addString(FILE_NAME, identifiersUrl, JOB_PARAMETER_DEFAULT_IDENTIFYING_VALUE); - } catch (Exception e) { - var msg = String.format("Failed to read %s, reason: %s", FilenameUtils.getBaseName(uploadedFilePath), e.getMessage()); - log.error(msg); - throw new FileOperationException(msg); - } - } - } - var jobId = jobCommand.getId().toString(); var outputFileName = fileNameResolver.resolve(jobCommand, workDir, jobId); diff --git a/src/main/java/org/folio/dew/service/UserReferenceService.java b/src/main/java/org/folio/dew/service/UserReferenceService.java index 56f0217c1..d850fd8dd 100644 --- a/src/main/java/org/folio/dew/service/UserReferenceService.java +++ b/src/main/java/org/folio/dew/service/UserReferenceService.java @@ -94,20 +94,6 @@ public String getPatronGroupNameById(String id, ErrorServiceArgs args) { } } - @Cacheable(cacheNames = "patronGroupIds") - public String getPatronGroupIdByName(String name) { - if (isEmpty(name)) { - throw new BulkEditException("Patron group can not be empty"); - } - var response = groupClient.getGroupByQuery(String.format("group==\"%s\"", name)); - if (response.getUsergroups().isEmpty()) { - var msg = "Invalid patron group value: " + name; - log.error(msg); - throw new BulkEditException(msg); - } - return response.getUsergroups().get(0).getId(); - } - @Cacheable(cacheNames = "customFields") public CustomField getCustomFieldByRefId(String refId) { return customFieldsClient.getCustomFieldsByQuery(getModuleId(MOD_USERS),String.format("refId==\"%s\"", refId)) @@ -116,14 +102,6 @@ public CustomField getCustomFieldByRefId(String refId) { .orElseThrow(() -> new BulkEditException(format("Custom field with refId=%s not found", refId))); } - @Cacheable(cacheNames = "customFields") - public CustomField getCustomFieldByName(String name) { - return customFieldsClient.getCustomFieldsByQuery(getModuleId(MOD_USERS), String.format("name==\"%s\"", name)) - .getCustomFields().stream().filter(customField -> customField.getName().equals(name)) - .findFirst() - .orElseThrow(() -> new BulkEditException(format("Custom field with name=%s not found", name))); - } - @Cacheable(cacheNames = "moduleIds") public String getModuleId(String moduleName) { var tenantId = folioExecutionContext.getTenantId(); diff --git a/src/main/java/org/folio/dew/service/mapper/MapperHelper.java b/src/main/java/org/folio/dew/service/mapper/MapperHelper.java deleted file mode 100644 index 89bbe5bfa..000000000 --- a/src/main/java/org/folio/dew/service/mapper/MapperHelper.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.folio.dew.service.mapper; - -import static org.apache.commons.lang3.StringUtils.isEmpty; - -import lombok.experimental.UtilityClass; - -@UtilityClass -public class MapperHelper { - public static String restoreStringValue(String s) { - return isEmpty(s) || "null".equalsIgnoreCase(s) ? null : s; - } - -} diff --git a/src/main/java/org/folio/dew/service/update/BulkEditHoldingsContentUpdateService.java b/src/main/java/org/folio/dew/service/update/BulkEditHoldingsContentUpdateService.java deleted file mode 100644 index 5841a224a..000000000 --- a/src/main/java/org/folio/dew/service/update/BulkEditHoldingsContentUpdateService.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.folio.dew.service.update; - -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.PREVIEW_FILE_NAME; -import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_FILE_PATH; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.Constants.COMMA; -import static org.folio.dew.utils.Constants.CSV_EXTENSION; -import static org.folio.dew.utils.Constants.FILE_NAME; -import static org.folio.dew.utils.Constants.IDENTIFIER_TYPE; -import static org.folio.dew.utils.Constants.NO_CHANGE_MESSAGE; -import static org.folio.dew.utils.Constants.PATH_SEPARATOR; -import static org.folio.dew.utils.Constants.PREVIEW_PREFIX; -import static org.folio.dew.utils.Constants.UPDATED_PREFIX; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.de.entity.JobCommand; -import org.folio.dew.domain.dto.HoldingsContentUpdate; -import org.folio.dew.domain.dto.HoldingsContentUpdateCollection; -import org.folio.dew.domain.dto.HoldingsFormat; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.error.FileOperationException; -import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.ContentUpdateRecords; -import org.folio.dew.service.UpdatesResult; -import org.folio.dew.service.validation.HoldingsContentUpdateValidatorService; -import org.folio.dew.utils.CsvHelper; -import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Objects; - -@Component -@RequiredArgsConstructor -@Log4j2 -public class BulkEditHoldingsContentUpdateService { - private final RemoteFilesStorage remoteFilesStorage; - private final BulkEditProcessingErrorsService errorsService; - private final HoldingsLocationUpdateStrategy locationUpdateStrategy; - private final HoldingsContentUpdateValidatorService validatorService; - - public UpdatesResult process(JobCommand jobCommand, HoldingsContentUpdateCollection contentUpdates) { - validatorService.validateContentUpdateCollection(contentUpdates); - try { - var fileName = FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION; - var updatedFileName = jobCommand.getId() + PATH_SEPARATOR + UPDATED_PREFIX + fileName; - var previewFileName = jobCommand.getId() + PATH_SEPARATOR + PREVIEW_PREFIX + fileName; - var holdingsFormats = CsvHelper.readRecordsFromStorage(remoteFilesStorage, jobCommand.getId() + PATH_SEPARATOR + fileName, HoldingsFormat.class, true); - var updatedHoldings = applyContentUpdates(holdingsFormats, contentUpdates, jobCommand); - CsvHelper.saveRecordsToStorage(remoteFilesStorage, updatedHoldings.getUpdated(), HoldingsFormat.class, updatedFileName); - CsvHelper.saveRecordsToStorage(remoteFilesStorage, updatedHoldings.getPreview(), HoldingsFormat.class, previewFileName); - jobCommand.setJobParameters(new JobParametersBuilder(jobCommand.getJobParameters()) - .addString(UPDATED_FILE_NAME, updatedFileName) - .addString(PREVIEW_FILE_NAME, previewFileName) - .toJobParameters()); - jobCommand.setExportType(BULK_EDIT_UPDATE); - return new UpdatesResult().withTotal(holdingsFormats.size()).withEntitiesForPreview(updatedHoldings.getPreview()); - } catch (Exception e) { - var msg = String.format("I/O exception for job id %s, reason: %s", jobCommand.getId(), e.getMessage()); - log.error(msg); - throw new FileOperationException(msg); - } - } - - private ContentUpdateRecords applyContentUpdates(List holdingsFormats, HoldingsContentUpdateCollection contentUpdateCollection, JobCommand jobCommand) { - var updateResult = new ContentUpdateRecords(); - var errorStringBuilder = new StringBuilder(); - holdingsFormats.forEach(holdingsFormat -> { - var updatedHoldingsRecord = holdingsFormat; - if ("MARC".equals(holdingsFormat.getSource())) { - errorStringBuilder - .append(holdingsFormat.getIdentifier(jobCommand.getJobParameters().getString(IDENTIFIER_TYPE))) - .append(COMMA) - .append("Holdings records that have source \"MARC\" cannot be changed") - .append(System.lineSeparator()); - } else { - for (HoldingsContentUpdate contentUpdate: contentUpdateCollection.getHoldingsContentUpdates()) { - updatedHoldingsRecord = resolveUpdateStrategy(contentUpdate).applyUpdate(updatedHoldingsRecord, contentUpdate); - } - if (!Objects.equals(updatedHoldingsRecord, holdingsFormat)) { - updateResult.addToUpdated(updatedHoldingsRecord); - } else { - errorStringBuilder - .append(holdingsFormat.getIdentifier(jobCommand.getJobParameters().getString(IDENTIFIER_TYPE))) - .append(COMMA) - .append(NO_CHANGE_MESSAGE) - .append(System.lineSeparator()); - } - } - updateResult.addToPreview(updatedHoldingsRecord); - }); - if (!errorStringBuilder.toString().isEmpty()) { - errorsService.saveErrorInCSV(jobCommand.getId().toString(), errorStringBuilder.toString(), FilenameUtils.getName(jobCommand.getJobParameters().getString(FILE_NAME))); - } - return updateResult; - } - - private UpdateStrategy resolveUpdateStrategy(HoldingsContentUpdate update) { - switch (update.getOption()) { - case PERMANENT_LOCATION: - case TEMPORARY_LOCATION: - return locationUpdateStrategy; - default: - throw new BulkEditException(String.format("Content updates for %s not implemented", update.getOption())); - } - } -} diff --git a/src/main/java/org/folio/dew/service/update/BulkEditUserContentUpdateService.java b/src/main/java/org/folio/dew/service/update/BulkEditUserContentUpdateService.java deleted file mode 100644 index a955a05c5..000000000 --- a/src/main/java/org/folio/dew/service/update/BulkEditUserContentUpdateService.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.folio.dew.service.update; - -import static java.lang.String.format; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.PREVIEW_FILE_NAME; -import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_FILE_PATH; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.Constants.CSV_EXTENSION; -import static org.folio.dew.utils.Constants.FILE_NAME; -import static org.folio.dew.utils.Constants.IDENTIFIER_TYPE; -import static org.folio.dew.utils.Constants.NO_CHANGE_MESSAGE; -import static org.folio.dew.utils.Constants.PATH_SEPARATOR; -import static org.folio.dew.utils.Constants.PREVIEW_PREFIX; -import static org.folio.dew.utils.Constants.UPDATED_PREFIX; - -import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.folio.de.entity.JobCommand; -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateCollection; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.error.FileOperationException; -import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.ContentUpdateRecords; -import org.folio.dew.service.UpdatesResult; -import org.folio.dew.service.validation.UserContentUpdateValidatorService; -import org.folio.dew.utils.CsvHelper; -import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Objects; - -@Component -@RequiredArgsConstructor -@Log4j2 -public class BulkEditUserContentUpdateService { - private final RemoteFilesStorage remoteFilesStorage; - private final BulkEditProcessingErrorsService errorsService; - private final EmailUpdateStrategy emailUpdateStrategy; - private final ExpirationDateUpdateStrategy expirationDateUpdateStrategy; - private final PatronGroupUpdateStrategy patronGroupUpdateStrategy; - private final UserContentUpdateValidatorService validatorService; - - public UpdatesResult process(JobCommand jobCommand, UserContentUpdateCollection contentUpdates) { - validatorService.validateContentUpdateCollection(contentUpdates); - try { - log.info("process:: Processing content updates for job id {}", jobCommand.getId()); - var fileName = FilenameUtils.getName(jobCommand.getJobParameters().getString(TEMP_OUTPUT_FILE_PATH)) + CSV_EXTENSION; - var updatedFileName = jobCommand.getId() + PATH_SEPARATOR + UPDATED_PREFIX + fileName; - var previewFileName = jobCommand.getId() + PATH_SEPARATOR + PREVIEW_PREFIX + fileName; - var userFormats = CsvHelper.readRecordsFromStorage(remoteFilesStorage, jobCommand.getId() + PATH_SEPARATOR + fileName, UserFormat.class, true); - log.info("process:: Reading of file {} complete, number of userFormats: {}", fileName, userFormats.size()); - var contentUpdatedUsers = applyContentUpdates(userFormats, contentUpdates, jobCommand); - log.info("process:: Finished processing content updates: {} records, {} preview", contentUpdatedUsers.getUpdated().size(), contentUpdatedUsers.getPreview().size()); - CsvHelper.saveRecordsToStorage(remoteFilesStorage, contentUpdatedUsers.getUpdated(), UserFormat.class, updatedFileName); - CsvHelper.saveRecordsToStorage(remoteFilesStorage, contentUpdatedUsers.getPreview(), UserFormat.class, previewFileName); - jobCommand.setJobParameters(new JobParametersBuilder(jobCommand.getJobParameters()) - .addString(UPDATED_FILE_NAME, updatedFileName) - .addString(PREVIEW_FILE_NAME, previewFileName) - .toJobParameters()); - jobCommand.setExportType(BULK_EDIT_UPDATE); - return new UpdatesResult().withTotal(userFormats.size()).withEntitiesForPreview(contentUpdatedUsers.getPreview()); - } catch (Exception e) { - var msg = String.format("I/O exception for job id %s, reason: %s", jobCommand.getId(), e.getMessage()); - log.error(msg); - throw new FileOperationException(msg); - } - } - - private ContentUpdateRecords applyContentUpdates(List userFormats, UserContentUpdateCollection contentUpdateCollection, JobCommand jobCommand) { - var updateResult = new ContentUpdateRecords(); - userFormats.forEach(userFormat -> { - var updatedUser = userFormat; - for (UserContentUpdate contentUpdate: contentUpdateCollection.getUserContentUpdates()) { - try { - updatedUser = resolveUpdateStrategy(contentUpdate).applyUpdate(updatedUser, contentUpdate); - } catch (BulkEditException e) { - log.error("User content update {} was not applied for user {}, reason: {}", contentUpdate.getOption(), userFormat.getIdentifier(jobCommand.getJobParameters().getString(IDENTIFIER_TYPE)), e.getMessage()); - errorsService.saveErrorInCSV(jobCommand.getId().toString(), userFormat.getIdentifier(jobCommand.getJobParameters().getString(IDENTIFIER_TYPE)), e, FilenameUtils.getName(jobCommand.getJobParameters().getString(FILE_NAME))); - } - } - if (!Objects.equals(updatedUser, userFormat)) { - updateResult.addToUpdated(updatedUser); - } else { - errorsService.saveErrorInCSV(jobCommand.getId().toString(), userFormat.getIdentifier(jobCommand.getJobParameters().getString(IDENTIFIER_TYPE)), new BulkEditException(NO_CHANGE_MESSAGE), FilenameUtils.getName(jobCommand.getJobParameters().getString(FILE_NAME))); - } - updateResult.addToPreview(updatedUser); - }); - return updateResult; - } - - private UpdateStrategy resolveUpdateStrategy(UserContentUpdate update) { - switch (update.getOption()) { - case PATRON_GROUP: - return patronGroupUpdateStrategy; - case EXPIRATION_DATE: - return expirationDateUpdateStrategy; - case EMAIL_ADDRESS: - return emailUpdateStrategy; - default: - throw new BulkEditException(format("Content updates for %s not implemented", update.getOption())); - } - } -} diff --git a/src/main/java/org/folio/dew/service/update/EmailUpdateStrategy.java b/src/main/java/org/folio/dew/service/update/EmailUpdateStrategy.java deleted file mode 100644 index 3f2c11f73..000000000 --- a/src/main/java/org/folio/dew/service/update/EmailUpdateStrategy.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.folio.dew.service.update; - -import lombok.extern.log4j.Log4j2; -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.error.BulkEditException; -import org.springframework.stereotype.Component; - -@Component -@Log4j2 -public class EmailUpdateStrategy implements UpdateStrategy { - @Override - public UserFormat applyUpdate(UserFormat userFormat, UserContentUpdate update) { - var findValue = update.getActions().get(0).getValue().toString(); - var replaceWithValue = update.getActions().get(1).getValue().toString(); - if (userFormat.getEmail().contains(findValue)) { - return userFormat.withEmail(userFormat.getEmail().replace(findValue, replaceWithValue)); - } - throw new BulkEditException("Email does not match find criteria"); - } -} diff --git a/src/main/java/org/folio/dew/service/update/ExpirationDateUpdateStrategy.java b/src/main/java/org/folio/dew/service/update/ExpirationDateUpdateStrategy.java deleted file mode 100644 index c4ff55708..000000000 --- a/src/main/java/org/folio/dew/service/update/ExpirationDateUpdateStrategy.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.folio.dew.service.update; - -import static org.folio.dew.utils.BulkEditProcessorHelper.dateFromString; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserFormat; -import org.springframework.stereotype.Component; - -import java.util.Date; - -@Component -public class ExpirationDateUpdateStrategy implements UpdateStrategy { - @Override - public UserFormat applyUpdate(UserFormat userFormat, UserContentUpdate update) { - var action = update.getActions().get(0); - return userFormat - .withExpirationDate(action.getValue().toString()) - .withActive(Boolean.toString(dateFromString(action.getValue().toString()).after(new Date()))); - } -} diff --git a/src/main/java/org/folio/dew/service/update/HoldingsLocationUpdateStrategy.java b/src/main/java/org/folio/dew/service/update/HoldingsLocationUpdateStrategy.java deleted file mode 100644 index 0c743ba50..000000000 --- a/src/main/java/org/folio/dew/service/update/HoldingsLocationUpdateStrategy.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.folio.dew.service.update; - -import static org.apache.commons.lang3.StringUtils.EMPTY; - -import org.folio.dew.domain.dto.HoldingsContentUpdate; -import org.folio.dew.domain.dto.HoldingsFormat; -import org.springframework.stereotype.Component; - -@Component -public class HoldingsLocationUpdateStrategy implements UpdateStrategy { - @Override - public HoldingsFormat applyUpdate(HoldingsFormat holdingsFormat, HoldingsContentUpdate update) { - switch (update.getAction()) { - case REPLACE_WITH: - return replaceLocation(holdingsFormat, update); - case CLEAR_FIELD: - return clearLocation(holdingsFormat); - default: - return holdingsFormat; - } - } - - private HoldingsFormat replaceLocation(HoldingsFormat holdingsFormat, HoldingsContentUpdate update) { - var newLocation = update.getValue().toString(); - switch (update.getOption()) { - case PERMANENT_LOCATION: - return holdingsFormat - .withPermanentLocation(newLocation); - case TEMPORARY_LOCATION: - return holdingsFormat - .withTemporaryLocation(newLocation); - default: - return holdingsFormat; - } - } - - private HoldingsFormat clearLocation(HoldingsFormat holdingsFormat) { - return holdingsFormat - .withTemporaryLocation(EMPTY); - } -} diff --git a/src/main/java/org/folio/dew/service/update/PatronGroupUpdateStrategy.java b/src/main/java/org/folio/dew/service/update/PatronGroupUpdateStrategy.java deleted file mode 100644 index eddfbe888..000000000 --- a/src/main/java/org/folio/dew/service/update/PatronGroupUpdateStrategy.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.folio.dew.service.update; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserFormat; -import org.springframework.stereotype.Component; - -@Component -public class PatronGroupUpdateStrategy implements UpdateStrategy { - @Override - public UserFormat applyUpdate(UserFormat userFormat, UserContentUpdate update) { - return userFormat.withPatronGroup(update.getActions().get(0).getValue().toString()); - } -} diff --git a/src/main/java/org/folio/dew/service/update/UpdateStrategy.java b/src/main/java/org/folio/dew/service/update/UpdateStrategy.java deleted file mode 100644 index 583b033bf..000000000 --- a/src/main/java/org/folio/dew/service/update/UpdateStrategy.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.folio.dew.service.update; - -public interface UpdateStrategy { - T applyUpdate(T entity, U update); -} diff --git a/src/main/java/org/folio/dew/service/validation/ContentUpdateValidator.java b/src/main/java/org/folio/dew/service/validation/ContentUpdateValidator.java deleted file mode 100644 index 4f06f8552..000000000 --- a/src/main/java/org/folio/dew/service/validation/ContentUpdateValidator.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.folio.dew.service.validation; - -public interface ContentUpdateValidator { - boolean isValid(T update); -} diff --git a/src/main/java/org/folio/dew/service/validation/EmailUpdateValidator.java b/src/main/java/org/folio/dew/service/validation/EmailUpdateValidator.java deleted file mode 100644 index cdf15fe4d..000000000 --- a/src/main/java/org/folio/dew/service/validation/EmailUpdateValidator.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.folio.dew.service.validation; - -import static java.util.Objects.nonNull; -import static org.apache.commons.lang3.ObjectUtils.isEmpty; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.FIND; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.REPLACE_WITH; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.error.ContentUpdateValidationException; -import org.springframework.stereotype.Component; - -import java.util.Objects; - -@Component -public class EmailUpdateValidator implements ContentUpdateValidator { - @Override - public boolean isValid(UserContentUpdate update) { - String errorMessage = null; - if (update.getActions().size() == 2) { - var findAction = update.getActions().get(0); - var replaceWithAction = update.getActions().get(1); - if (FIND != findAction.getName() || REPLACE_WITH != replaceWithAction.getName()) { - errorMessage = "Email update must contain FIND action followed by REPLACE_WITH action"; - } else if (isEmpty(findAction.getValue()) || isEmpty(replaceWithAction.getValue())) { - errorMessage = "FIND and REPLACE_WITH values cannot be null or empty"; - } else if (Objects.equals(findAction.getValue(), replaceWithAction.getValue())) { - errorMessage = "FIND and REPLACE_WITH values cannot be equal"; - } - } else { - errorMessage = "Email update must contain FIND action followed by REPLACE_WITH action"; - } - if (nonNull(errorMessage)) { - throw new ContentUpdateValidationException(errorMessage); - } - return true; - } -} diff --git a/src/main/java/org/folio/dew/service/validation/ExpirationDateUpdateValidator.java b/src/main/java/org/folio/dew/service/validation/ExpirationDateUpdateValidator.java deleted file mode 100644 index 1929da053..000000000 --- a/src/main/java/org/folio/dew/service/validation/ExpirationDateUpdateValidator.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.folio.dew.service.validation; - -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; -import static org.apache.commons.lang3.ObjectUtils.isEmpty; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.REPLACE_WITH; -import static org.folio.dew.utils.Constants.DATE_TIME_PATTERN; - -import lombok.extern.log4j.Log4j2; -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.error.ContentUpdateValidationException; -import org.springframework.stereotype.Component; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; - -@Component -@Log4j2 -public class ExpirationDateUpdateValidator implements ContentUpdateValidator { - @Override - public boolean isValid(UserContentUpdate update) { - String errorMessage = null; - var action = update.getActions().size() == 1 ? update.getActions().get(0) : null; - if (isNull(action) || REPLACE_WITH != action.getName()) { - errorMessage = "Expiration date update should consist of single REPLACE_WITH action"; - } else if (isEmpty(action.getValue())) { - errorMessage = "Value cannot be empty"; - } else { - try { - LocalDateTime.parse(action.getValue().toString(), DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)); - } catch (DateTimeParseException e) { - errorMessage = String.format("Invalid date format: %s, expected yyyy-MM-dd HH:mm:ss.SSSX", action.getValue().toString()); - log.error(errorMessage); - } - } - if (nonNull(errorMessage)) { - throw new ContentUpdateValidationException(errorMessage); - } - return true; - } -} diff --git a/src/main/java/org/folio/dew/service/validation/HoldingsContentUpdateValidatorService.java b/src/main/java/org/folio/dew/service/validation/HoldingsContentUpdateValidatorService.java deleted file mode 100644 index 40ce0bb2f..000000000 --- a/src/main/java/org/folio/dew/service/validation/HoldingsContentUpdateValidatorService.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.folio.dew.service.validation; - -import lombok.RequiredArgsConstructor; -import org.folio.dew.domain.dto.HoldingsContentUpdate; -import org.folio.dew.domain.dto.HoldingsContentUpdateCollection; -import org.folio.dew.error.ContentUpdateValidationException; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class HoldingsContentUpdateValidatorService { - private final HoldingsLocationUpdateValidator locationUpdateValidator; - - public boolean validateContentUpdateCollection(HoldingsContentUpdateCollection contentUpdateCollection) { - return contentUpdateCollection.getHoldingsContentUpdates().stream() - .allMatch(this::isValidContentUpdate); - } - - private boolean isValidContentUpdate(HoldingsContentUpdate update) { - return resolveValidator(update).isValid(update); - } - - private ContentUpdateValidator resolveValidator(HoldingsContentUpdate update) { - switch (update.getOption()) { - case TEMPORARY_LOCATION: - case PERMANENT_LOCATION: - return locationUpdateValidator; - default: - throw new ContentUpdateValidationException(update.getOption() + " update is not supported"); - } - } -} diff --git a/src/main/java/org/folio/dew/service/validation/HoldingsLocationUpdateValidator.java b/src/main/java/org/folio/dew/service/validation/HoldingsLocationUpdateValidator.java deleted file mode 100644 index 22ce5afb8..000000000 --- a/src/main/java/org/folio/dew/service/validation/HoldingsLocationUpdateValidator.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.folio.dew.service.validation; - -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; -import static org.folio.dew.domain.dto.HoldingsContentUpdate.ActionEnum.REPLACE_WITH; -import static org.folio.dew.domain.dto.HoldingsContentUpdate.OptionEnum.PERMANENT_LOCATION; - -import lombok.RequiredArgsConstructor; -import org.folio.dew.domain.dto.HoldingsContentUpdate; -import org.folio.dew.error.BulkEditException; -import org.folio.dew.error.ContentUpdateValidationException; -import org.folio.dew.service.HoldingsReferenceService; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class HoldingsLocationUpdateValidator implements ContentUpdateValidator { - private final HoldingsReferenceService referenceService; - @Override - public boolean isValid(HoldingsContentUpdate update) { - String errorMessage = null; - if (REPLACE_WITH == update.getAction()) { - try { - if (isNull(update.getValue())) { - errorMessage = "Location name cannot be empty"; - } - var locationName = update.getValue().toString(); - referenceService.getLocationByName(locationName); - } catch (BulkEditException e) { - errorMessage = "Location does not exist"; - } - } else if (PERMANENT_LOCATION == update.getOption()) { - errorMessage = "Permanent location cannot be cleared"; - } - if (nonNull(errorMessage)) { - throw new ContentUpdateValidationException(errorMessage); - } - return true; - } -} diff --git a/src/main/java/org/folio/dew/service/validation/PatronGroupUpdateValidator.java b/src/main/java/org/folio/dew/service/validation/PatronGroupUpdateValidator.java deleted file mode 100644 index bcc9453cd..000000000 --- a/src/main/java/org/folio/dew/service/validation/PatronGroupUpdateValidator.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.folio.dew.service.validation; - -import static java.util.Objects.nonNull; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.REPLACE_WITH; - -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.ObjectUtils; -import org.folio.dew.client.GroupClient; -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.error.ContentUpdateValidationException; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class PatronGroupUpdateValidator implements ContentUpdateValidator { - private final GroupClient groupClient; - @Override - public boolean isValid(UserContentUpdate update) { - String errorMessage = null; - if (update.getActions().size() != 1) { - errorMessage = "Patron group update should consist of single REPLACE_WITH action"; - } else { - var action = update.getActions().get(0); - if (REPLACE_WITH != action.getName()) { - errorMessage = action.getName() + " cannot be applied to Patron group"; - } else if (ObjectUtils.isEmpty(action.getValue())) { - errorMessage = "REPLACE_WITH value cannot be null or empty"; - } else if (groupClient.getGroupByQuery(String.format("group==\"%s\"", action.getValue().toString())).getUsergroups().isEmpty()) { - errorMessage = "Non-existing patron group: " + action.getValue().toString(); - } - } - if (nonNull(errorMessage)) { - throw new ContentUpdateValidationException(errorMessage); - } - return true; - } -} diff --git a/src/main/java/org/folio/dew/service/validation/UserContentUpdateValidatorService.java b/src/main/java/org/folio/dew/service/validation/UserContentUpdateValidatorService.java deleted file mode 100644 index dd0d8ce85..000000000 --- a/src/main/java/org/folio/dew/service/validation/UserContentUpdateValidatorService.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.folio.dew.service.validation; - -import lombok.RequiredArgsConstructor; -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateCollection; -import org.folio.dew.error.ContentUpdateValidationException; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class UserContentUpdateValidatorService { - private final ExpirationDateUpdateValidator expirationDateUpdateValidator; - private final PatronGroupUpdateValidator patronGroupUpdateValidator; - private final EmailUpdateValidator emailUpdateValidator; - - public boolean validateContentUpdateCollection(UserContentUpdateCollection contentUpdateCollection) { - return contentUpdateCollection.getUserContentUpdates().stream() - .allMatch(this::isValidContentUpdate); - } - - private boolean isValidContentUpdate(UserContentUpdate update) { - return resolveValidator(update).isValid(update); - } - - private ContentUpdateValidator resolveValidator(UserContentUpdate update) { - switch (update.getOption()) { - case EXPIRATION_DATE: - return expirationDateUpdateValidator; - case PATRON_GROUP: - return patronGroupUpdateValidator; - case EMAIL_ADDRESS: - return emailUpdateValidator; - default: - throw new ContentUpdateValidationException(update.getOption() + " update is not supported"); - } - } -} diff --git a/src/main/java/org/folio/dew/utils/CsvHelper.java b/src/main/java/org/folio/dew/utils/CsvHelper.java index 4d0b2405a..c2d1aa3ae 100644 --- a/src/main/java/org/folio/dew/utils/CsvHelper.java +++ b/src/main/java/org/folio/dew/utils/CsvHelper.java @@ -82,9 +82,9 @@ public static void saveRecordsToStorage(R storag } } - public static long countLines(R storage, String path, boolean skipHeaders) throws IOException { + public static long countLines(R storage, String path) throws IOException { try (var lines = storage.lines(path)) { - return skipHeaders ? lines.count() - 1 : lines.count(); + return lines.count(); } } } diff --git a/src/main/resources/swagger.api/bulk-edit.yaml b/src/main/resources/swagger.api/bulk-edit.yaml index 15299b86e..a55c1b4ba 100644 --- a/src/main/resources/swagger.api/bulk-edit.yaml +++ b/src/main/resources/swagger.api/bulk-edit.yaml @@ -5,481 +5,6 @@ info: servers: - url: /bulk-edit/ paths: - /{jobId}/item-content-update/upload: - post: - description: Upload item content updates - operationId: postItemContentUpdates - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - - in: query - name: limit - required: false - schema: - type: integer - description: The numbers of records to return - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/itemContentUpdateCollection" - responses: - "200": - description: Collection of items for preview - content: - application/json: - schema: - $ref: "#/components/schemas/itemCollection" - "400": - description: Bad request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "404": - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "500": - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/user-content-update/upload: - post: - description: Upload user content updates - operationId: postUserContentUpdates - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - - in: query - name: limit - required: false - schema: - type: integer - description: The numbers of records to return - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/userContentUpdateCollection" - responses: - "200": - description: Collection of users for preview - content: - application/json: - schema: - $ref: "#/components/schemas/userCollection" - "400": - description: Bad request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "404": - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "500": - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/holdings-content-update/upload: - post: - description: Upload holdings record content updates - operationId: postHoldingsContentUpdates - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - - in: query - name: limit - required: false - schema: - type: integer - description: The numbers of records to return - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/holdingsContentUpdateCollection" - responses: - "200": - description: Collection of holdings records for preview - content: - application/json: - schema: - $ref: "#/components/schemas/holdingsRecordCollection" - "400": - description: Bad request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "404": - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "500": - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/preview/updated-items/download: - get: - description: Download updated items preview as csv-file - operationId: downloadItemsPreviewByJobId - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - responses: - '200': - description: Preview of updated items to download - content: - text/csv: - schema: - type: string - format: binary - "400": - description: Bad request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "404": - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "500": - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/preview/updated-users/download: - get: - description: Download updated users preview as csv-file - operationId: downloadUsersPreviewByJobId - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - responses: - '200': - description: Preview of updated items to download - content: - text/csv: - schema: - type: string - format: binary - "400": - description: Bad request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "404": - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "500": - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/preview/updated-holdings/download: - get: - description: Download updated holdings records preview as csv-file - operationId: downloadHoldingsPreviewByJobId - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - responses: - '200': - description: Preview of updated holdings to download - content: - text/csv: - schema: - type: string - format: binary - "400": - description: Bad request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "404": - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - "500": - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/preview/users: - get: - description: Get a list of users for preview - operationId: getPreviewUsersByJobId - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - - in: query - name: limit - required: true - schema: - type: integer - description: The numbers of users to return - responses: - '200': - description: Collection of users for preview - content: - application/json: - schema: - $ref: "#/components/schemas/userCollection" - '400': - description: Bad Request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - '404': - description: Bad Request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - '500': - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/preview/items: - get: - description: Get a list of items for preview - operationId: getPreviewItemsByJobId - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - - in: query - name: limit - required: true - schema: - type: integer - description: The numbers of items to return - responses: - '200': - description: Collection of items for preview - content: - application/json: - schema: - $ref: "#/components/schemas/itemCollection" - '400': - description: Bad Request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - '404': - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - '500': - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/preview/holdings: - get: - description: Get a list of holdings for preview - operationId: getPreviewHoldingsByJobId - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - - in: query - name: limit - required: true - schema: - type: integer - description: The numbers of holdings to return - responses: - '200': - description: Collection of holdings for preview - content: - application/json: - schema: - $ref: "#/components/schemas/holdingsRecordCollection" - '400': - description: Bad Request - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - '404': - description: Not found - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - '500': - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - /{jobId}/errors: - get: - description: Get a list of errors for preview - operationId: getErrorsPreviewByJobId - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - - in: query - name: limit - required: true - schema: - type: integer - description: The numbers of users to return - responses: - '200': - description: Collection of users for preview - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" - '404': - description: No found - content: - text/plain: - schema: - type: string - example: Job not found - '500': - description: Internal server errors, e.g. due to misconfiguration - content: - text/plain: - schema: - type: string - example: Internal server error /{jobId}/upload: post: description: Upload csv file @@ -564,32 +89,6 @@ paths: $ref: "#/components/examples/errors" schema: $ref: "#/components/schemas/errors" - /{jobId}/roll-back: - post: - description: Roll back csv file - operationId: rollBackCsvFile - parameters: - - name: jobId - in: path - required: true - description: UUID of the JobCommand - schema: - $ref: "#/components/schemas/UUID" - responses: - "200": - description: Csv file roll back uploaded - content: - text/plain: - schema: - type: string - "500": - description: Internal server errors, e.g. due to misconfiguration - content: - application/json: - example: - $ref: "#/components/examples/errors" - schema: - $ref: "#/components/schemas/errors" components: schemas: UUID: @@ -641,10 +140,6 @@ components: $ref: '../../../../folio-export-common/schemas/inventory/electronicAccessRelationshipCollection.json#/ElectronicAccessRelationshipCollection' statisticalCodes: $ref: '../../../../folio-export-common/schemas/inventory/statisticalCodeCollection.json#/StatisticalCodeCollection' - itemContentUpdateCollection: - $ref: '../../../../folio-export-common/schemas/bulk-edit/itemContentUpdateCollection.json#/ItemContentUpdateCollection' - userContentUpdateCollection: - $ref: '../../../../folio-export-common/schemas/bulk-edit/userContentUpdateCollection.json#/UserContentUpdateCollection' customFieldCollection: $ref: '../../../../folio-export-common/schemas/user/customFieldCollection.json#/CustomFieldCollection' holdingsRecordCollection: diff --git a/src/test/java/org/folio/dew/BulkEditTest.java b/src/test/java/org/folio/dew/BulkEditTest.java index f398f041e..7e78e41b5 100644 --- a/src/test/java/org/folio/dew/BulkEditTest.java +++ b/src/test/java/org/folio/dew/BulkEditTest.java @@ -16,18 +16,13 @@ import org.folio.dew.domain.dto.IdentifierType; import org.folio.dew.domain.dto.JobParameterNames; import org.folio.dew.repository.LocalFilesStorage; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.update.BulkEditHoldingsContentUpdateService; -import org.folio.dew.utils.Constants; import org.folio.spring.FolioExecutionContext; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; @@ -54,7 +49,6 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.UUID; @@ -79,7 +73,6 @@ import static org.folio.dew.domain.dto.JobParameterNames.TEMP_LOCAL_MARC_PATH; import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_FILE_PATH; import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_MARC_PATH; -import static org.folio.dew.service.FolioExecutionContextManager.X_OKAPI_TENANT; import static org.folio.dew.utils.Constants.BULKEDIT_DIR_NAME; import static org.folio.dew.utils.Constants.ENTITY_TYPE; import static org.folio.dew.utils.Constants.EXPORT_TYPE; @@ -110,12 +103,12 @@ class BulkEditTest extends BaseBatchTest { private static final String EXPECTED_HOLDINGS_OUTPUT_BY_ITEM_BARCODE_CSV = "src/test/resources/output/bulk_edit_holdings_records_by_item_barcode.csv"; private static final String ITEM_IDENTIFIERS_BAD_REFERENCE_IDS_CSV = "src/test/resources/upload/item_identifiers_bad_reference.csv"; private static final String EXPECTED_ITEMS_OUTPUT_BAD_REFERENCE_CSV = "src/test/resources/output/bulk_edit_items_reference_not_found.csv"; - private final static String EXPECTED_ITEM_OUTPUT_BAD_REFERENCE_ERRORS = "src/test/resources/output/bulk_edit_items_bad_reference_errors.csv"; + private static final String EXPECTED_ITEM_OUTPUT_BAD_REFERENCE_ERRORS = "src/test/resources/output/bulk_edit_items_bad_reference_errors.csv"; private static final String ITEM_IDENTIFIERS_EMPTY_REFERENCE_IDS_CSV = "src/test/resources/upload/item_identifiers_empty_reference.csv"; private static final String EXPECTED_ITEM_OUTPUT_EMPTY_REFERENCE_CSV = "src/test/resources/output/bulk_edit_items_empty_reference.csv"; private static final String USER_IDENTIFIERS_BAD_REFERENCE_IDS_CSV = "src/test/resources/upload/user_identifiers_bad_reference.csv"; private static final String EXPECTED_USER_OUTPUT_BAD_REFERENCE_CSV = "src/test/resources/output/bulk_edit_users_reference_not_found.csv"; - private final static String EXPECTED_USER_OUTPUT_BAD_REFERENCE_ERRORS = "src/test/resources/output/bulk_edit_users_bad_reference_errors.csv"; + private static final String EXPECTED_USER_OUTPUT_BAD_REFERENCE_ERRORS = "src/test/resources/output/bulk_edit_users_bad_reference_errors.csv"; private static final String USER_IDENTIFIERS_EMPTY_REFERENCE_IDS_CSV = "src/test/resources/upload/user_identifiers_empty_reference.csv"; private static final String EXPECTED_USER_OUTPUT_EMPTY_REFERENCE_CSV = "src/test/resources/output/bulk_edit_users_empty_reference.csv"; private static final String BARCODES_CSV = "src/test/resources/upload/barcodes.csv"; @@ -130,17 +123,9 @@ class BulkEditTest extends BaseBatchTest { private static final String INSTANCE_ISSN_ISBN_CSV = "src/test/resources/upload/instance_ISSN_ISBN.csv"; private static final String ITEM_BARCODES_DOUBLE_QOUTES_CSV = "src/test/resources/upload/item_barcodes_double_qoutes.csv"; private static final String ITEM_HOLDINGS_CSV = "src/test/resources/upload/item_holdings.csv"; - private static final String USER_RECORD_CSV = "src/test/resources/upload/bulk_edit_user_record.csv"; - private static final String USER_RECORD_CSV_NOT_FOUND = "src/test/resources/upload/bulk_edit_user_record_not_found.csv"; - private static final String USER_RECORD_CSV_BAD_CONTENT = "src/test/resources/upload/bulk_edit_user_record_bad_content.csv"; - private static final String USER_RECORD_CSV_BAD_CUSTOM_FIELD = "src/test/resources/upload/bulk_edit_user_record_bad_custom_field.csv"; - private static final String USER_RECORD_CSV_EMPTY_PATRON_GROUP = "src/test/resources/upload/bulk_edit_user_record_empty_patron_group.csv"; - private static final String USER_RECORD_ROLLBACK_CSV = "test-directory/bulk_edit_rollback.csv"; private static final String BARCODES_SOME_NOT_FOUND = "src/test/resources/upload/barcodesSomeNotFound.csv"; private static final String ITEM_BARCODES_SOME_NOT_FOUND = "src/test/resources/upload/item_barcodes_some_not_found.csv"; private static final String INSTANCE_HRIDS_SOME_NOT_FOUND = "src/test/resources/upload/instance_hrids_some_not_found.csv"; - private static final String USERS_QUERY_FILE_PATH = "src/test/resources/upload/users_by_group.cql"; - private static final String ITEMS_QUERY_FILE_PATH = "src/test/resources/upload/items_by_barcode.cql"; private static final String QUERY_NO_GROUP_FILE_PATH = "src/test/resources/upload/active_no_group.cql"; private static final String EXPECTED_BULK_EDIT_USER_OUTPUT = "src/test/resources/output/bulk_edit_user_identifiers_output.csv"; private static final String EXPECTED_BULK_EDIT_USER_PREFERRED_EMAIL_OUTPUT = "src/test/resources/output/bulk_edit_user_identifiers_preferred_email_output.csv"; @@ -153,7 +138,6 @@ class BulkEditTest extends BaseBatchTest { private static final String EXPECTED_BULK_EDIT_INSTANCE_JSON_OUTPUT = "src/test/resources/output/bulk_edit_instance_identifiers_json_output.json"; private static final String EXPECTED_BULK_EDIT_INSTANCE_BY_ISSN_JSON_OUTPUT = "src/test/resources/output/bulk_edit_instance_by_issn_json_output.json"; private static final String EXPECTED_BULK_EDIT_INSTANCE_BY_ISBN_JSON_OUTPUT = "src/test/resources/output/bulk_edit_instance_by_isbn_json_output.json"; - private static final String EXPECTED_BULK_EDIT_ITEM_QUERY_JSON_OUTPUT = "src/test/resources/output/bulk_edit_item_query_json_output.json"; private static final String EXPECTED_BULK_EDIT_HOLDINGS_OUTPUT = "src/test/resources/output/bulk_edit_holdings_records_output.csv"; private static final String EXPECTED_BULK_EDIT_HOLDINGS_JSON_OUTPUT = "src/test/resources/output/bulk_edit_holdings_records_json_output.json"; @@ -162,18 +146,17 @@ class BulkEditTest extends BaseBatchTest { private static final String EXPECTED_BULK_EDIT_HOLDINGS_OUTPUT_ITEM_BARCODE = "src/test/resources/output/bulk_edit_holdings_records_output_item_barcode.csv"; private static final String EXPECTED_BULK_EDIT_ITEM_OUTPUT_ESCAPED = "src/test/resources/output/bulk_edit_item_identifiers_output_escaped.csv"; private static final String EXPECTED_NO_GROUP_OUTPUT = "src/test/resources/output/bulk_edit_no_group_output.csv"; - private static final String EXPECTED_ITEMS_QUERY_OUTPUT = "src/test/resources/output/bulk_edit_item_query_output.csv"; - private final static String EXPECTED_BULK_EDIT_OUTPUT_SOME_NOT_FOUND = "src/test/resources/output/bulk_edit_user_identifiers_output_some_not_found.csv"; - private final static String EXPECTED_BULK_EDIT_ITEM_OUTPUT_SOME_NOT_FOUND = "src/test/resources/output/bulk_edit_item_identifiers_output_some_not_found.csv"; - private final static String EXPECTED_BULK_EDIT_INSTANCE_OUTPUT_SOME_NOT_FOUND = "src/test/resources/output/bulk_edit_instance_identifiers_output_some_not_found.csv"; - private final static String EXPECTED_BULK_EDIT_OUTPUT_ERRORS = "src/test/resources/output/bulk_edit_user_identifiers_errors_output.csv"; - private final static String EXPECTED_BULK_EDIT_ITEM_OUTPUT_ERRORS = "src/test/resources/output/bulk_edit_item_identifiers_errors_output.csv"; - private final static String EXPECTED_BULK_EDIT_INSTANCE_OUTPUT_ERRORS = "src/test/resources/output/bulk_edit_instance_identifiers_errors_output.csv"; - private final static String EXPECTED_BULK_EDIT_HOLDINGS_ERRORS = "src/test/resources/output/bulk_edit_holdings_records_errors_output.csv"; - private final static String EXPECTED_BULK_EDIT_HOLDINGS_BAD_REFERENCE_IDS_ERRORS = "src/test/resources/output/bulk_edit_holdings_records_bad_reference_ids_errors_output.csv"; - private final static String EXPECTED_BULK_EDIT_HOLDINGS_ERRORS_INST_HRID = "src/test/resources/output/bulk_edit_holdings_records_errors_output_inst_hrid.csv"; + private static final String EXPECTED_BULK_EDIT_OUTPUT_SOME_NOT_FOUND = "src/test/resources/output/bulk_edit_user_identifiers_output_some_not_found.csv"; + private static final String EXPECTED_BULK_EDIT_ITEM_OUTPUT_SOME_NOT_FOUND = "src/test/resources/output/bulk_edit_item_identifiers_output_some_not_found.csv"; + private static final String EXPECTED_BULK_EDIT_INSTANCE_OUTPUT_SOME_NOT_FOUND = "src/test/resources/output/bulk_edit_instance_identifiers_output_some_not_found.csv"; + private static final String EXPECTED_BULK_EDIT_OUTPUT_ERRORS = "src/test/resources/output/bulk_edit_user_identifiers_errors_output.csv"; + private static final String EXPECTED_BULK_EDIT_ITEM_OUTPUT_ERRORS = "src/test/resources/output/bulk_edit_item_identifiers_errors_output.csv"; + private static final String EXPECTED_BULK_EDIT_INSTANCE_OUTPUT_ERRORS = "src/test/resources/output/bulk_edit_instance_identifiers_errors_output.csv"; + private static final String EXPECTED_BULK_EDIT_HOLDINGS_ERRORS = "src/test/resources/output/bulk_edit_holdings_records_errors_output.csv"; + private static final String EXPECTED_BULK_EDIT_HOLDINGS_BAD_REFERENCE_IDS_ERRORS = "src/test/resources/output/bulk_edit_holdings_records_bad_reference_ids_errors_output.csv"; + private static final String EXPECTED_BULK_EDIT_HOLDINGS_ERRORS_INST_HRID = "src/test/resources/output/bulk_edit_holdings_records_errors_output_inst_hrid.csv"; private static final String EXPECTED_BULK_EDIT_HOLDINGS_ERRORS_ITEM_BARCODE = "src/test/resources/output/bulk_edit_holdings_records_errors_output_item_barcode.csv"; - private final static String EXPECTED_BULK_EDIT_ITEM_IDENTIFIERS_HOLDINGS_ERRORS_OUTPUT = "src/test/resources/output/bulk_edit_item_identifiers_holdings_errors_output.csv"; + private static final String EXPECTED_BULK_EDIT_ITEM_IDENTIFIERS_HOLDINGS_ERRORS_OUTPUT = "src/test/resources/output/bulk_edit_item_identifiers_holdings_errors_output.csv"; @Autowired @@ -190,19 +173,7 @@ class BulkEditTest extends BaseBatchTest { @Autowired private Job bulkEditItemCqlJob; @Autowired - private Job bulkEditUpdateUserRecordsJob; - @Autowired - private Job bulkEditUpdateItemRecordsJob; - @Autowired - private Job bulkEditRollBackJob; - @Autowired - private Job bulkEditUpdateHoldingsRecordsJob; - @Autowired - private BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - @Autowired private LocalFilesStorage localFilesStorage; - @Autowired - private BulkEditHoldingsContentUpdateService bulkEditHoldingsContentUpdateService; @MockBean private InstanceClient instanceClient; @MockBean @@ -334,7 +305,7 @@ void uploadMarcInstanceIdentifiersJobTest(String identifierType, String path) th FilenameUtils.removeExtension((new File(path)).getName()) + "E" + FilenameUtils.getExtension(path); parametersBuilder.addString(FILE_NAME, file); localFilesStorage.write(file, Files.readAllBytes(of)); - parametersBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, file, false), false); + parametersBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, file), false); var tempDir = getTempDirWithSeparatorSuffix() + springApplicationName + PATH_SEPARATOR + jobId; var tempFile = tempDir + PATH_SEPARATOR + of.getFileName(); @@ -385,7 +356,7 @@ void uploadMarcInstanceIdentifiersInvalidContentJobTest() throws Exception { FilenameUtils.removeExtension((new File(path)).getName()) + "E" + FilenameUtils.getExtension(path); parametersBuilder.addString(FILE_NAME, file); localFilesStorage.write(file, Files.readAllBytes(of)); - parametersBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, file, false), false); + parametersBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, file), false); var tempDir = getTempDirWithSeparatorSuffix() + springApplicationName + PATH_SEPARATOR + jobId; var tempFile = tempDir + PATH_SEPARATOR + of.getFileName(); @@ -613,19 +584,6 @@ void bulkEditInstanceJobTestWithErrors() throws Exception { assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED); } - @Test - @DisplayName("Run bulk-edit (user query) successfully") - void bulkEditUserQueryJobTest() throws Exception { - JobLauncherTestUtils testLauncher = createTestLauncher(bulkEditUserCqlJob); - - final JobParameters jobParameters = prepareJobParameters(ExportType.BULK_EDIT_QUERY, USER, BARCODE, USERS_QUERY_FILE_PATH); - JobExecution jobExecution = testLauncher.launchJob(jobParameters); - - verifyCsvAndJsonOutput(jobExecution, EXPECTED_BULK_EDIT_USER_OUTPUT, EXPECTED_BULK_EDIT_USER_JSON_OUTPUT); - - assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED); - } - @Test @DisplayName("Process users without patron group id successfully") void shouldProcessUsersWithoutPatronGroupIdSuccessfully() throws Exception { @@ -639,65 +597,6 @@ void shouldProcessUsersWithoutPatronGroupIdSuccessfully() throws Exception { assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED); } - @Test - @Deprecated - @Disabled - @DisplayName("Run bulk-edit (item query) successfully") - void bulkEditItemQueryJobTest() throws Exception { - mockInstanceClient(); - - JobLauncherTestUtils testLauncher = createTestLauncher(bulkEditItemCqlJob); - when(folioExecutionContext.getAllHeaders()).thenReturn(Map.of(X_OKAPI_TENANT, List.of("original"))); - - final JobParameters jobParameters = prepareJobParameters(ExportType.BULK_EDIT_QUERY, ITEM, BARCODE, ITEMS_QUERY_FILE_PATH); - JobExecution jobExecution = testLauncher.launchJob(jobParameters); - - verifyCsvAndJsonOutput(jobExecution, EXPECTED_ITEMS_QUERY_OUTPUT, EXPECTED_BULK_EDIT_ITEM_QUERY_JSON_OUTPUT); - - assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED); - } - - @Disabled - // TODO uncomment when resolved - @ParameterizedTest - @ValueSource(strings = {USER_RECORD_CSV, USER_RECORD_CSV_NOT_FOUND, USER_RECORD_CSV_BAD_CONTENT, USER_RECORD_CSV_BAD_CUSTOM_FIELD, USER_RECORD_CSV_EMPTY_PATRON_GROUP}) - @DisplayName("Run update user records w/ and w/o errors") - void uploadUserRecordsJobTest(String csvFileName) throws Exception { - JobLauncherTestUtils testLauncher = createTestLauncher(bulkEditUpdateUserRecordsJob); - final JobParameters jobParameters = prepareJobParameters(BULK_EDIT_UPDATE, USER, BARCODE, csvFileName); - JobExecution jobExecution = testLauncher.launchJob(jobParameters); - - assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED); - - var errors = bulkEditProcessingErrorsService.readErrorsFromCSV(jobExecution.getJobParameters().getString("jobId"), csvFileName, 10); - - if (!USER_RECORD_CSV.equals(csvFileName)) { - if (USER_RECORD_CSV_BAD_CUSTOM_FIELD.equals(csvFileName)) { - assertThat(errors.getErrors()).hasSize(2); - } else { - assertThat(errors.getErrors()).hasSize(1); - } - assertThat(jobExecution.getExecutionContext().getString(OUTPUT_FILES_IN_STORAGE)).isNotEmpty(); - } else { - assertThat(jobExecution.getExecutionContext().getString(OUTPUT_FILES_IN_STORAGE)).isNotEmpty(); - assertThat(errors.getErrors()).isEmpty(); - } - } - - @Disabled - // TODO uncomment when resolved - @Test - @DisplayName("Run rollback user records successfully") - void rollBackUserRecordsJobTest() throws Exception { - JobLauncherTestUtils testLauncher = createTestLauncher(bulkEditRollBackJob); - localFilesStorage.write(USER_RECORD_ROLLBACK_CSV, Files.readAllBytes(new File(USER_RECORD_CSV).toPath())); - var parametersBuilder = new JobParametersBuilder(); - parametersBuilder.addString(Constants.JOB_ID, "74914e57-3406-4757-938b-9a3f718d0ee6"); - parametersBuilder.addString(FILE_NAME, USER_RECORD_ROLLBACK_CSV); - JobExecution jobExecution = testLauncher.launchJob(parametersBuilder.toJobParameters()); - assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED); - } - @Test @DisplayName("Double quotes in data should be escaped") @SneakyThrows @@ -820,7 +719,7 @@ private JobParameters prepareJobParameters(ExportType exportType, EntityType ent var file = getWorkingDirectory("mod-data-export-worker", BULKEDIT_DIR_NAME) + FileNameUtils.getBaseName(path) + "E" + FileNameUtils.getExtension(path); parametersBuilder.addString(FILE_NAME, file); localFilesStorage.write(file, Files.readAllBytes(of)); - parametersBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, file, false), false); + parametersBuilder.addLong(TOTAL_CSV_LINES, countLines(localFilesStorage, file), false); } var tempDir = getTempDirWithSeparatorSuffix() + springApplicationName + PATH_SEPARATOR + jobId; diff --git a/src/test/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditFilterUserRecordsForRollBackProcessorTest.java b/src/test/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditFilterUserRecordsForRollBackProcessorTest.java deleted file mode 100644 index 211f55693..000000000 --- a/src/test/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditFilterUserRecordsForRollBackProcessorTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.rollbackjob; - -import org.folio.dew.domain.dto.User; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.service.BulkEditParseService; -import org.folio.dew.service.BulkEditRollBackService; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class BulkEditFilterUserRecordsForRollBackProcessorTest { - - @Mock - private BulkEditRollBackService bulkEditRollBackService; - @Mock - private BulkEditParseService bulkEditParseService; - - @InjectMocks - private BulkEditFilterUserRecordsForRollBackProcessor processor; - - @Test - void testWriteIfUserBeRollBack() { - var userFormat = new UserFormat(); - userFormat.setId("userId"); - var user= new User(); - user.setId("userId"); - - when(bulkEditRollBackService.isUserBeRollBack(isA(String.class), isA(UUID.class))).thenReturn(true); - when(bulkEditParseService.mapUserFormatToUser(isA(UserFormat.class))).thenReturn(user); - - processor.setJobId("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var processedUser = processor.process(userFormat); - verify(bulkEditParseService, times(1)).mapUserFormatToUser(isA(UserFormat.class)); - assertNotNull(processedUser); - } - - @Test - void testWriteIfUserNotBeRollBack() { - var userFormat = new UserFormat(); - userFormat.setId("userId"); - - when(bulkEditRollBackService.isUserBeRollBack(isA(String.class), isA(UUID.class))).thenReturn(false); - - processor.setJobId("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var user = processor.process(userFormat); - verify(bulkEditParseService, times(0)).mapUserFormatToUser(isA(UserFormat.class)); - assertNull(user); - } -} diff --git a/src/test/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsForRollBackCsvWriterTest.java b/src/test/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsForRollBackCsvWriterTest.java deleted file mode 100644 index ebd4e7354..000000000 --- a/src/test/java/org/folio/dew/batch/bulkedit/jobs/rollbackjob/BulkEditUpdateUserRecordsForRollBackCsvWriterTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.folio.dew.batch.bulkedit.jobs.rollbackjob; - -import org.folio.dew.client.UserClient; -import org.folio.dew.domain.dto.User; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.batch.item.Chunk; - -import java.util.List; - -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -@ExtendWith(MockitoExtension.class) -class BulkEditUpdateUserRecordsForRollBackCsvWriterTest { - - @Mock - private UserClient userClient; - @InjectMocks - private BulkEditUpdateUserRecordsForRollBackWriter writer; - - @Test - void writeTest() throws Exception { - var user1 = new User(); - user1.setId("1"); - var user2 = new User(); - user2.setId("2"); - var users = List.of(user1, user2); - - doNothing().when(userClient).updateUser(isA(User.class), isA(String.class)); - writer.write(new Chunk<>(users)); - verify(userClient, times(2)).updateUser(isA(User.class), isA(String.class)); - } -} diff --git a/src/test/java/org/folio/dew/controller/BulkEditControllerTest.java b/src/test/java/org/folio/dew/controller/BulkEditControllerTest.java index 4f767b208..a4f0239b6 100644 --- a/src/test/java/org/folio/dew/controller/BulkEditControllerTest.java +++ b/src/test/java/org/folio/dew/controller/BulkEditControllerTest.java @@ -1,49 +1,27 @@ package org.folio.dew.controller; import static java.lang.String.format; -import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.folio.dew.domain.dto.EntityType.HOLDINGS_RECORD; import static org.folio.dew.domain.dto.EntityType.USER; import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_IDENTIFIERS; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_QUERY; import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; import static org.folio.dew.domain.dto.IdentifierType.BARCODE; -import static org.folio.dew.domain.dto.JobParameterNames.PREVIEW_FILE_NAME; import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_FILE_PATH; import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.FIND; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.REPLACE_WITH; -import static org.folio.dew.utils.Constants.CSV_EXTENSION; import static org.folio.dew.utils.Constants.FILE_NAME; -import static org.folio.dew.utils.Constants.PATH_SEPARATOR; import static org.folio.dew.utils.Constants.UPDATED_PREFIX; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.isA; -import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.springframework.batch.test.AssertFile.assertFileEquals; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.Date; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -54,475 +32,39 @@ import org.folio.de.entity.JobCommand; import org.folio.de.entity.JobCommandType; import org.folio.dew.BaseBatchTest; -import org.folio.dew.client.ConfigurationClient; -import org.folio.dew.client.GroupClient; -import org.folio.dew.client.InventoryClient; import org.folio.dew.client.UserClient; import org.folio.dew.domain.dto.EntityType; import org.folio.dew.domain.dto.ExportType; -import org.folio.dew.domain.dto.HoldingsRecordCollection; import org.folio.dew.domain.dto.IdentifierType; -import org.folio.dew.domain.dto.Item; -import org.folio.dew.domain.dto.ItemCollection; -import org.folio.dew.domain.dto.JobParameterNames; import org.folio.dew.domain.dto.Metadata; import org.folio.dew.domain.dto.Personal; import org.folio.dew.domain.dto.User; -import org.folio.dew.domain.dto.UserCollection; -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateAction; -import org.folio.dew.domain.dto.UserContentUpdateCollection; -import org.folio.dew.domain.dto.UserGroup; -import org.folio.dew.domain.dto.UserGroupCollection; -import org.folio.dew.error.BulkEditException; import org.folio.dew.error.FileOperationException; -import org.folio.dew.repository.JobCommandRepository; import org.folio.dew.repository.LocalFilesStorage; -import org.folio.dew.repository.RemoteFilesStorage; -import org.folio.dew.service.BulkEditProcessingErrorsService; -import org.folio.dew.service.BulkEditRollBackService; import org.folio.dew.service.JobCommandsReceiverService; -import org.folio.spring.DefaultFolioExecutionContext; -import org.folio.spring.FolioExecutionContext; -import org.folio.spring.FolioModuleMetadata; -import org.folio.spring.integration.XOkapiHeaders; -import org.folio.spring.scope.FolioExecutionContextSetter; -import org.folio.tenant.domain.dto.Errors; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.ArgumentCaptor; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobExecutionException; -import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.batch.integration.launch.JobLaunchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.core.io.FileSystemResource; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; class BulkEditControllerTest extends BaseBatchTest { private static final String UPLOAD_URL_TEMPLATE = "/bulk-edit/%s/upload"; - private static final String START_URL_TEMPLATE = "/bulk-edit/%s/start"; - private static final String PREVIEW_USERS_URL_TEMPLATE = "/bulk-edit/%s/preview/users"; - private static final String PREVIEW_ITEMS_URL_TEMPLATE = "/bulk-edit/%s/preview/items"; - private static final String PREVIEW_HOLDINGS_RECORD_URL_TEMPLATE = "/bulk-edit/%s/preview/holdings"; - private static final String ERRORS_URL_TEMPLATE = "/bulk-edit/%s/errors"; - private static final String ITEMS_CONTENT_UPDATE_UPLOAD_URL_TEMPLATE = "/bulk-edit/%s/item-content-update/upload"; - private static final String USERS_CONTENT_UPDATE_UPLOAD_URL_TEMPLATE = "/bulk-edit/%s/user-content-update/upload"; - private static final String HOLDINGS_CONTENT_UPDATE_UPLOAD_URL_TEMPLATE = "/bulk-edit/%s/holdings-content-update/upload"; - private static final String ITEMS_CONTENT_PREVIEW_DOWNLOAD_URL_TEMPLATE = "/bulk-edit/%s/preview/updated-items/download"; - private static final String USERS_CONTENT_PREVIEW_DOWNLOAD_URL_TEMPLATE = "/bulk-edit/%s/preview/updated-users/download"; - private static final String ITEMS_FOR_LOCATION_UPDATE = "src/test/resources/upload/bulk_edit_items_for_location_update.csv"; - private static final String ITEMS_FOR_LOAN_TYPE_UPDATE = "src/test/resources/upload/bulk_edit_items_for_loan_type_update.csv"; - private static final String ITEMS_FOR_STATUS_UPDATE = "src/test/resources/upload/bulk_edit_items_for_status_update.csv"; - private static final String ITEM_FOR_STATUS_UPDATE_ERROR = "src/test/resources/upload/bulk_edit_item_for_status_update_error.csv"; - private static final String ITEMS_FOR_NOTHING_UPDATE = "src/test/resources/upload/bulk_edit_items_for_nothing_update.csv"; private static final String USER_DATA = "src/test/resources/upload/user_data.csv"; private static final String ITEM_DATA = "src/test/resources/upload/item_data.csv"; - private static final String PREVIEW_USER_DATA = "src/test/resources/upload/preview_user_data.csv"; - private static final String PREVIEW_ITEM_DATA = "src/test/resources/upload/preview_item_data.csv"; - private static final String PREVIEW_HOLDINGS_RECORD_DATA = "src/test/resources/upload/preview_holdings_record_data.csv"; - private static final String EXPECTED_ERRORS_FOR_CLEAR_PATRON_GROUP = "src/test/resources/output/expected_errors_for_clear_patron_group.json"; - private static final String EXPECTED_USER_CONTENT_UPDATE_OUTPUT = "src/test/resources/output/bulk_edit_user_content_updates_expected_output.csv"; - private static final String HOLDINGS_RECORDS_FOR_UPDATE = "src/test/resources/output/bulk_edit_holdings_records_output.csv"; - private static final String UPDATED_HOLDINGS_RECORDS_JSON = "src/test/resources/output/bulk_edit_updated_holdings_records_output.json"; private static final UUID JOB_ID = UUID.randomUUID(); - public static final String LIMIT = "limit"; - - @MockBean - private BulkEditRollBackService bulkEditRollBackService; @MockBean private UserClient userClient; - @MockBean - private InventoryClient inventoryClient; - - @MockBean - private JobCommandRepository jobCommandRepository; - @MockBean private JobCommandsReceiverService jobCommandsReceiverService; - @MockBean - private ConfigurationClient configurationClient; - - @Autowired - private BulkEditProcessingErrorsService bulkEditProcessingErrorsService; - - @Autowired - private RemoteFilesStorage remoteFilesStorage; - @Autowired private LocalFilesStorage localFilesStorage; - @Autowired - private BulkEditProcessingErrorsService errorsService; - - @Autowired - private org.springframework.batch.core.Job bulkEditProcessUserIdentifiersJob; - - @Autowired - private FolioModuleMetadata folioModuleMetadata; - - @Autowired - private FolioExecutionContext folioExecutionContext; - - @MockBean - private GroupClient groupClient; - - @Test - void shouldReturnErrorsPreview() throws Exception { - - var jobId = JOB_ID; - var jobCommand = createBulkEditJobRequest(jobId, BULK_EDIT_IDENTIFIERS, USER, BARCODE); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - int numOfErrorLines = 3; - int errorsPreviewLimit = 2; - var reasonForError = new BulkEditException("Record not found"); - var fileName = "barcodes.csv"; - for (int i = 0; i < numOfErrorLines; i++) { - bulkEditProcessingErrorsService.saveErrorInCSV(jobId.toString(), String.valueOf(i), reasonForError, fileName); - } - var headers = defaultHeaders(); - - var response = mockMvc.perform(get(format(ERRORS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(errorsPreviewLimit))) - .andExpect(status().isOk()); - - var errors = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), Errors.class); - - assertThat(errors.getErrors(), hasSize(errorsPreviewLimit)); - assertThat(errors.getTotalRecords(), is(errorsPreviewLimit)); - - bulkEditProcessingErrorsService.removeTemporaryErrorStorage(); - } - - @Test - void shouldReturnEmptyErrorsForErrorsPreview() throws Exception { - - var jobId = JOB_ID; - var jobCommand = createBulkEditJobRequest(jobId, BULK_EDIT_IDENTIFIERS, USER, BARCODE); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var expectedErrorMsg = format("errors file for job id %s", jobId); - - var headers = defaultHeaders(); - - var response = mockMvc.perform(get(format(ERRORS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(2))) - .andExpect(status().isOk()); - - var errors = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), Errors.class); - - assertThat(errors.getErrors(), empty()); - assertThat(errors.getTotalRecords(), is(0)); - } - - @Test - void shouldReturnErrorsFileNotFoundErrorForErrorsPreview() throws Exception { - - var jobId = JOB_ID; - var expectedJson = String.format("{\"errors\":[{\"message\":\"JobCommand with id %s doesn't exist.\",\"type\":\"-1\",\"code\":\"Not found\",\"parameters\":null}],\"total_records\":1}", jobId); - - var headers = defaultHeaders(); - - mockMvc.perform(get(format(ERRORS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(2))) - .andExpect(status().isNotFound()) - .andExpect(content().json(expectedJson)); - } - - @SneakyThrows - @Test - void shouldReturnCompleteUserPreviewForQuery() { - var query = "(patronGroup==\"3684a786-6671-4268-8ed0-9db82ebca60b\") sortby personal.lastName"; - when(userClient.getUserByQuery(query, 3)).thenReturn(buildUserCollection()); - - var jobId = UUID.randomUUID(); - var jobCommand = createBulkEditJobRequest(jobId, BULK_EDIT_QUERY, USER, BARCODE); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - - var response = mockMvc.perform(get(format(PREVIEW_USERS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(3))) - .andExpect(status().isOk()); - - var users = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), UserCollection.class); - assertThat(users.getTotalRecords(), equalTo(3)); - assertThat(users.getUsers(), hasSize(3)); - } - - @Disabled - // TODO uncomment when resolved - @SneakyThrows - @ParameterizedTest - @EnumSource(value = IdentifierType.class, - names = {"ID", "BARCODE", "EXTERNAL_SYSTEM_ID", "USER_NAME"}, - mode = EnumSource.Mode.INCLUDE) - void shouldReturnCompleteUserPreviewForAnyIdentifier(IdentifierType identifierType) { - when(groupClient.getGroupByQuery("group==\"PatronGroup\"")) - .thenReturn(new UserGroupCollection().usergroups(List.of(new UserGroup().group("PatronGroup") - .desc("Staff Member").id("3684a786-6671-4268-8ed0-9db82ebca60b").expirationOffsetInDays(730))).totalRecords(1)); - remoteFilesStorage.upload(FilenameUtils.getName(PREVIEW_USER_DATA), PREVIEW_USER_DATA); - var jobId = UUID.randomUUID(); - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_IDENTIFIERS); - jobCommand.setEntityType(USER); - jobCommand.setIdentifierType(identifierType); - jobCommand.setJobParameters(new JobParametersBuilder() - .addString(TEMP_OUTPUT_FILE_PATH, "test/path/" + PREVIEW_USER_DATA.replace(CSV_EXTENSION, EMPTY)) - .toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - var response = mockMvc.perform(get(format(PREVIEW_USERS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(3))) - .andExpect(status().isOk()); - - var users = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), UserCollection.class); - assertThat(users.getTotalRecords(), equalTo(3)); - assertThat(users.getUsers(), hasSize(3)); - } - - @ParameterizedTest - @EnumSource(value = IdentifierType.class, names = {"ID", "HOLDINGS_RECORD_ID", "INSTANCE_HRID", "ITEM_BARCODE"}) - @SneakyThrows - void shouldReturnCompleteHoldingsRecordPreview(IdentifierType identifierType) { - var jobId = UUID.randomUUID(); - remoteFilesStorage.upload(jobId + PATH_SEPARATOR + FilenameUtils.getName(PREVIEW_HOLDINGS_RECORD_DATA), PREVIEW_HOLDINGS_RECORD_DATA); - - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_IDENTIFIERS); - jobCommand.setEntityType(HOLDINGS_RECORD); - jobCommand.setIdentifierType(identifierType); - jobCommand.setJobParameters(new JobParametersBuilder() - .addString(TEMP_OUTPUT_FILE_PATH, "test/path/" + PREVIEW_HOLDINGS_RECORD_DATA.replace(CSV_EXTENSION, EMPTY)) - .toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - var response = mockMvc.perform(get(format(PREVIEW_HOLDINGS_RECORD_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(1))) - .andExpect(status().isOk()); - - var holdingsRecord = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), HoldingsRecordCollection.class); - assertThat(holdingsRecord.getTotalRecords(), equalTo(1)); - assertThat(holdingsRecord.getHoldingsRecords(), hasSize(1)); - } - - @ParameterizedTest - @EnumSource(value = IdentifierType.class, names = {"ID", "HOLDINGS_RECORD_ID", "INSTANCE_HRID", "ITEM_BARCODE"}) - @SneakyThrows - void shouldReturnChangedHoldingsRecordPreview(IdentifierType identifierType) { - var jobId = UUID.randomUUID(); - remoteFilesStorage.upload(jobId + PATH_SEPARATOR + FilenameUtils.getName(PREVIEW_HOLDINGS_RECORD_DATA), PREVIEW_HOLDINGS_RECORD_DATA); - - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_UPDATE); - jobCommand.setEntityType(HOLDINGS_RECORD); - jobCommand.setIdentifierType(identifierType); - jobCommand.setJobParameters(new JobParametersBuilder() - .addString(UPDATED_FILE_NAME, jobId + PATH_SEPARATOR + FilenameUtils.getName(PREVIEW_HOLDINGS_RECORD_DATA).replace(CSV_EXTENSION, EMPTY)) - .toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - var response = mockMvc.perform(get(format(PREVIEW_HOLDINGS_RECORD_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(1))) - .andExpect(status().isOk()); - - var holdingsRecord = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), HoldingsRecordCollection.class); - assertThat(holdingsRecord.getTotalRecords(), equalTo(1)); - assertThat(holdingsRecord.getHoldingsRecords(), hasSize(1)); - } - - @SneakyThrows - @ParameterizedTest - @EnumSource(value = IdentifierType.class, - names = {"ID", "BARCODE", "EXTERNAL_SYSTEM_ID", "USER_NAME"}, - mode = EnumSource.Mode.INCLUDE) - void shouldReturnEmptyUserPreviewIfNoRecordsAvailable(IdentifierType identifierType) { - var jobId = UUID.randomUUID(); - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_IDENTIFIERS); - jobCommand.setEntityType(USER); - jobCommand.setIdentifierType(identifierType); - jobCommand.setJobParameters(new JobParametersBuilder() - .addString(TEMP_OUTPUT_FILE_PATH, "test/path/no_file") - .toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - var response = mockMvc.perform(get(format(PREVIEW_USERS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(3))) - .andExpect(status().isOk()); - - var users = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), UserCollection.class); - assertThat(users.getTotalRecords(), equalTo(0)); - assertThat(users.getUsers(), hasSize(0)); - } - - @ParameterizedTest - @EnumSource(value = IdentifierType.class, names = {"EXTERNAL_SYSTEM_ID", "USER_NAME"}, mode = EnumSource.Mode.EXCLUDE) - @SneakyThrows - void shouldReturnEmptyItemPreviewIfNoRecordsAvailable(IdentifierType identifierType) { - var jobId = UUID.randomUUID(); - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_IDENTIFIERS); - jobCommand.setEntityType(USER); - jobCommand.setIdentifierType(identifierType); - jobCommand.setJobParameters(new JobParametersBuilder() - .addString(TEMP_OUTPUT_FILE_PATH, "test/path/no_file") - .toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - var response = mockMvc.perform(get(format(PREVIEW_ITEMS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(3))) - .andExpect(status().isOk()); - - var items = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), ItemCollection.class); - assertThat(items.getTotalRecords(), equalTo(0)); - assertThat(items.getItems(), hasSize(0)); - } - - @ParameterizedTest - @EnumSource(value = IdentifierType.class, names = {"ID", "HOLDINGS_RECORD_ID", "INSTANCE_HRID", "ITEM_BARCODE"}) - @SneakyThrows - void shouldReturnEmptyHoldingsRecordPreviewIfNoRecordsAvailable(IdentifierType identifierType) { - var jobId = UUID.randomUUID(); - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_IDENTIFIERS); - jobCommand.setEntityType(HOLDINGS_RECORD); - jobCommand.setIdentifierType(identifierType); - jobCommand.setJobParameters(new JobParametersBuilder() - .addString(TEMP_OUTPUT_FILE_PATH, "test/path/no_file") - .toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - var response = mockMvc.perform(get(format(PREVIEW_HOLDINGS_RECORD_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(1))) - .andExpect(status().isOk()); - - var holdingsRecord = objectMapper.readValue(response.andReturn().getResponse().getContentAsString(), HoldingsRecordCollection.class); - assertThat(holdingsRecord.getTotalRecords(), equalTo(0)); - assertThat(holdingsRecord.getHoldingsRecords(), hasSize(0)); - } - - @SneakyThrows - @ParameterizedTest - @CsvSource({"BULK_EDIT_UPDATE,barcode==(\"123\" OR \"456\")", - "BULK_EDIT_QUERY,(patronGroup==\"3684a786-6671-4268-8ed0-9db82ebca60b\") sortby personal.lastName"}) - void shouldReturnCompleteUserPreviewWithLimitControl(String exportType, String query) { - - var jobId = UUID.randomUUID(); - var jobCommand = createBulkEditJobRequest(jobId, ExportType.fromValue(exportType), USER, BARCODE); - - when(userClient.getUserByQuery(query, 2)).thenReturn(buildUserCollection()); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - - var response = mockMvc.perform(get(format(PREVIEW_USERS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(2))) - .andExpect(status().isOk()); - - ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor limitCaptor = ArgumentCaptor.forClass(Long.class); - verify(userClient).getUserByQuery(queryCaptor.capture(), limitCaptor.capture()); - assertThat(query, equalTo(queryCaptor.getValue())); - assertThat(2L, equalTo(limitCaptor.getValue())); - } - - @Disabled("The source code is unsupported, so the test is invalid.") - @SneakyThrows - @ParameterizedTest - @EnumSource(value = EntityType.class, names = {"USER", "ITEM"}, mode = EnumSource.Mode.INCLUDE) - void shouldReturnCompleteUpdatePreviewWithLimitControl(EntityType entityType) { - var query = "barcode==(\"123\" OR \"456\")"; - var jobId = UUID.randomUUID(); - var jobCommand = createBulkEditJobRequest(jobId, BULK_EDIT_UPDATE, entityType, BARCODE); - when(inventoryClient.getItemByQuery(query, 2)).thenReturn(buildItemCollection()); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - - var response = mockMvc.perform(get(format(PREVIEW_ITEMS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(2))) - .andExpect(status().isOk()); - - ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor limitCaptor = ArgumentCaptor.forClass(Long.class); - verify(inventoryClient).getItemByQuery(queryCaptor.capture(), limitCaptor.capture()); - assertThat(query, equalTo(queryCaptor.getValue())); - assertThat(2L, equalTo(limitCaptor.getValue())); - } - - @SneakyThrows - @Test - void shouldReturnErrorForInvalidExportType() { - - var jobId = UUID.randomUUID(); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())) - .thenReturn(Optional.of(createBulkEditJobRequest(jobId, ExportType.ORDERS_EXPORT, USER, BARCODE))); - - var headers = defaultHeaders(); - - mockMvc.perform(get(format(PREVIEW_USERS_URL_TEMPLATE, jobId)) - .headers(headers) - .queryParam(LIMIT, String.valueOf(2))) - .andExpect(status().isBadRequest()); - } - - @SneakyThrows - @Test - void shouldReturnErrorJobNotFound() { - - var headers = defaultHeaders(); - - mockMvc.perform(get(format(PREVIEW_USERS_URL_TEMPLATE, UUID.randomUUID())) - .headers(headers) - .queryParam(LIMIT, String.valueOf(2))) - .andExpect(status().isNotFound()); - } - @Test @DisplayName("Launch job on upload file with identifiers successfully") @SneakyThrows @@ -548,27 +90,6 @@ void shouldLaunchJobAndReturnNumberOfRecordsOnIdentifiersFileUpload() { verify(exportJobManagerSync, times(1)).launchJob(any()); } - @Test - @DisplayName("Skip headers while counting records for update") - @SneakyThrows - void shouldSkipHeadersWhileCountingRecordsForUpdate() { - var jobId = UUID.randomUUID(); - var jobCommand = createBulkEditJobRequest(jobId, ExportType.BULK_EDIT_UPDATE, USER, BARCODE); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var headers = defaultHeaders(); - - var bytes = new FileInputStream("src/test/resources/upload/bulk_edit_user_record.csv").readAllBytes(); - var file = new MockMultipartFile("file", "bulk_edit_user_record.csv", MediaType.TEXT_PLAIN_VALUE, bytes); - - var result = mockMvc.perform(multipart(format(UPLOAD_URL_TEMPLATE, jobId)) - .file(file) - .headers(headers)) - .andExpect(status().isOk()) - .andReturn(); - assertThat(result.getResponse().getContentAsString(), equalTo("2")); - } - @Test @DisplayName("Upload empty file - BAD REQUEST") @SneakyThrows @@ -603,113 +124,6 @@ void shouldReturnNotFoundIfJobDoesNotExist() { .andExpect(status().isNotFound()); } - @Test - @DisplayName("Start update job test") - @SneakyThrows - void startUpdateJobTest() { - var jobId = UUID.fromString("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var jobCommand = new JobCommand(); - jobCommand.setExportType(ExportType.BULK_EDIT_UPDATE); - jobCommand.setEntityType(USER); - jobCommand.setJobParameters(new JobParametersBuilder().toJobParameters()); - var executionId = 0l; - var jobExecution = new JobExecution(executionId); - - var headers = defaultHeaders(); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - when(exportJobManagerSync.launchJob(isA(JobLaunchRequest.class))).thenReturn(jobExecution); - - mockMvc.perform(multipart(format(START_URL_TEMPLATE, jobId)) - .headers(headers)) - .andExpect(status().isOk()); - - verify(jobCommandsReceiverService, times(1)).getBulkEditJobCommandById(jobId.toString()); - verify(exportJobManagerSync, timeout(1000).times(1)).launchJob(isA(JobLaunchRequest.class)); - } - - @Test - @DisplayName("Job doesn't exist - NOT FOUND") - @SneakyThrows - void startUpdateJobReturnNotFoundTest() { - var jobId = UUID.fromString("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var headers = defaultHeaders(); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.empty()); - - mockMvc.perform(multipart(format(START_URL_TEMPLATE, jobId)) - .headers(headers)) - .andExpect(status().isNotFound()); - } - - @Test - @DisplayName("Start update job - INTERNAL SERVER ERROR") - @SneakyThrows - void startUpdateJobReturnInternalServerErrorTest() { - var jobId = UUID.fromString("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var jobCommand = new JobCommand(); - jobCommand.setExportType(ExportType.BULK_EDIT_UPDATE); - jobCommand.setEntityType(USER); - jobCommand.setJobParameters(new JobParametersBuilder().toJobParameters()); - - var headers = defaultHeaders(); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - when(exportJobManagerSync.launchJob(isA(JobLaunchRequest.class))).thenThrow(new JobExecutionException("Execution exception")); - - mockMvc.perform(multipart(format(START_URL_TEMPLATE, jobId)) - .headers(headers)) - .andExpect(status().isOk()); - } - - @ParameterizedTest - @ValueSource(strings = {"/bulk-edit/%s/preview/updated-users/download", "/bulk-edit/%s/preview/updated-holdings/download"}) - @SneakyThrows - @DisplayName("Download users/holdings preview when preview is not available - NOT FOUND") - void shouldReturnNotFoundIfPreviewIsNotAvailable(String urlTemplate) { - var jobCommand = new JobCommand(); - var jobId = UUID.randomUUID(); - jobCommand.setId(jobId); - jobCommand.setJobParameters(new JobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - mockMvc.perform(get(format(urlTemplate, jobId)) - .headers(defaultHeaders())) - .andExpect(status().isNotFound()); - } - - @ParameterizedTest - @CsvSource({"src/test/resources/upload/preview_user_data.csv,/bulk-edit/%s/preview/updated-users/download", - "src/test/resources/output/bulk_edit_holdings_records_output.csv,/bulk-edit/%s/preview/updated-holdings/download"}) - @SneakyThrows - @DisplayName("Download users/holdings preview - successful") - void shouldDownloadPreviewAfterUserContentUpdate(String previewPath, String urlTemplate) { - var fileName = FilenameUtils.getName(previewPath); - remoteFilesStorage.upload(fileName, previewPath); - var jobCommand = new JobCommand(); - var jobId = UUID.randomUUID(); - jobCommand.setId(jobId); - jobCommand.setJobParameters(new JobParametersBuilder().addString(PREVIEW_FILE_NAME, fileName).toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var response = mockMvc.perform(get(format(urlTemplate, jobId)) - .headers(defaultHeaders())) - .andExpect(status().isOk()) - .andReturn(); - - var expectedCsv = new FileSystemResource(previewPath); - var actualCsvByteArr = response.getResponse().getContentAsByteArray(); - Path actualDownloadedCsvTmp = Paths.get("actualDownloaded.csv"); - Files.write(actualDownloadedCsvTmp, actualCsvByteArr); - var actualCsv = new FileSystemResource(actualDownloadedCsvTmp); - - assertFileEquals(expectedCsv, actualCsv); - - Files.delete(actualDownloadedCsvTmp); - } - @Test @SneakyThrows void shouldReturnNumberOfRowsInCSVFile() { @@ -747,151 +161,6 @@ void shouldReturnNumberOfRowsInCSVFile() { // 3 lines loaded (+1 header because of BULK_EDIT_IDENTIFIERS job). assertThat(result.getResponse().getContentAsString(), equalTo("4")); - - jobId = UUID.randomUUID(); - var jobCommand2 = createBulkEditJobRequest(jobId, BULK_EDIT_UPDATE, USER, BARCODE); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand2)); - - headers = defaultHeaders(); - - bytes = new FileInputStream("src/test/resources/upload/bulk_edit_user_record_3_lines_edited_1_line.csv").readAllBytes(); - file = new MockMultipartFile("file", "bulk_edit_user_record_3_lines_edited_1_line.csv", MediaType.TEXT_PLAIN_VALUE, bytes); - - result = mockMvc.perform(multipart(format(UPLOAD_URL_TEMPLATE, jobId)) - .file(file) - .headers(headers)) - .andExpect(status().isOk()) - .andReturn(); - - // Edited only 1 line. - assertThat(result.getResponse().getContentAsString(), equalTo("3")); - - jobId = UUID.randomUUID(); - var jobCommand3 = createBulkEditJobRequest(jobId, BULK_EDIT_UPDATE, USER, BARCODE); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand3)); - - headers = defaultHeaders(); - - // Load initial file with no edited lines. - bytes = new FileInputStream("src/test/resources/upload/bulk_edit_user_record_3_lines.csv").readAllBytes(); - file = new MockMultipartFile("file", "bulk_edit_user_record_3_lines.csv", MediaType.TEXT_PLAIN_VALUE, bytes); - - result = mockMvc.perform(multipart(format(UPLOAD_URL_TEMPLATE, jobId)) - .file(file) - .headers(headers)) - .andExpect(status().isOk()) - .andReturn(); - - // Edited 0 lines. - assertThat(result.getResponse().getContentAsString(), equalTo("3")); - - jobId = UUID.randomUUID(); - var jobCommand4 = createBulkEditJobRequest(jobId, BULK_EDIT_UPDATE, USER, BARCODE); - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand4)); - - headers = defaultHeaders(); - - // Load edited file with incorrect number of tokens. - bytes = new FileInputStream("src/test/resources/upload/invalid-user-records-incorrect-number-of-tokens.csv").readAllBytes(); - file = new MockMultipartFile("file", "invalid-user-records-incorrect-number-of-tokens.csv", MediaType.TEXT_PLAIN_VALUE, bytes); - - result = mockMvc.perform(multipart(format(UPLOAD_URL_TEMPLATE, jobId)) - .file(file) - .headers(headers)) - .andExpect(status().isOk()) - .andReturn(); - - // Keep all 3 lines to delegate them into SkipListener. - assertThat(result.getResponse().getContentAsString(), equalTo("3")); - } - - @Test - @DisplayName("Post user content update to replace email") - @SneakyThrows - void shouldReplaceEmailAddress() { - when(userClient.getUserByQuery("barcode==\"123\"", 1)) - .thenReturn(new UserCollection().addUsersItem(new User().barcode("123").active(true).personal(new Personal().email("123@example1.com")) - .expirationDate(new Date()).patronGroup("3684a786-6671-4268-8ed0-9db82ebca60b")).totalRecords(1)); - when(userClient.getUserByQuery("barcode==\"456\"", 1)) - .thenReturn(new UserCollection().addUsersItem(new User().barcode("456").active(true).personal(new Personal().email("456@example2.com")) - .expirationDate(new Date()).patronGroup("3684a786-6671-4268-8ed0-9db82ebca60b")).totalRecords(1)); - when(userClient.getUserByQuery("barcode==\"789\"", 1)) - .thenReturn(new UserCollection().addUsersItem(new User().barcode("789").active(true).personal(new Personal().email("789@example3.com")) - .expirationDate(new Date()).patronGroup("3684a786-6671-4268-8ed0-9db82ebca60b")).totalRecords(1)); - UserGroup userGroup; - when(groupClient.getGroupById("3684a786-6671-4268-8ed0-9db82ebca60b")) - .thenReturn(userGroup = new UserGroup().group("some group").id("3684a786-6671-4268-8ed0-9db82ebca60b")); - when(groupClient.getGroupByQuery("group==\"some group\"")) - .thenReturn(new UserGroupCollection().usergroups(List.of(userGroup))); - - var jobId = UUID.randomUUID(); - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_IDENTIFIERS); - jobCommand.setEntityType(USER); - jobCommand.setIdentifierType(BARCODE); - jobCommand.setJobParameters(new JobParametersBuilder().addString(JobParameterNames.JOB_ID, jobId.toString()).toJobParameters()); - - when(jobCommandsReceiverService.getBulkEditJobCommandById(jobId.toString())).thenReturn(Optional.of(jobCommand)); - - var bytes = new FileInputStream("src/test/resources/upload/barcodes.csv").readAllBytes(); - var file = new MockMultipartFile("file", "barcodes.csv", MediaType.TEXT_PLAIN_VALUE, bytes); - - var responseUpload = mockMvc.perform(multipart(format(UPLOAD_URL_TEMPLATE, jobId)) - .file(file) - .headers(defaultHeaders())) - .andExpect(status().isOk()) - .andReturn(); - - Map> okapiHeaders = new LinkedHashMap<>(); - okapiHeaders.put(XOkapiHeaders.TENANT, List.of(TENANT)); - var defaultFolioExecutionContext = new DefaultFolioExecutionContext(folioModuleMetadata, okapiHeaders); - try (var context = new FolioExecutionContextSetter(defaultFolioExecutionContext)) { - - createTestLauncher(bulkEditProcessUserIdentifiersJob).launchJob(jobCommand.getJobParameters()); - - assertThat(responseUpload.getResponse().getContentAsString(), equalTo("3")); - - var updates = objectMapper.writeValueAsString(new UserContentUpdateCollection() - .userContentUpdates(List.of(new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EMAIL_ADDRESS) - .actions(List.of( - new UserContentUpdateAction().name(FIND).value("example1.com"), - new UserContentUpdateAction().name(REPLACE_WITH).value("NEWexample1.com"))), - new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EMAIL_ADDRESS) - .actions(List.of( - new UserContentUpdateAction().name(FIND).value("example2.com"), - new UserContentUpdateAction().name(REPLACE_WITH).value("NEWexample2.com"))), - new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EMAIL_ADDRESS) - .actions(List.of( - new UserContentUpdateAction().name(FIND).value("example3.com"), - new UserContentUpdateAction().name(REPLACE_WITH).value("NEWexample3.com"))))) - .totalRecords(3)); - - var responseContentUpdateUpload = mockMvc.perform(post(format(USERS_CONTENT_UPDATE_UPLOAD_URL_TEMPLATE, jobId)) - .headers(defaultHeaders()) - .content(updates)) - .andExpect(status().isOk()) - .andReturn(); - var actualUsers = objectMapper.readValue(responseContentUpdateUpload.getResponse().getContentAsString(), - UserCollection.class); - actualUsers.getUsers().forEach(u -> { - if (u.getBarcode().equals("123")) { - assertEquals("123@NEWexample1.com", u.getPersonal().getEmail()); - } else if (u.getBarcode().equals("456")) { - assertEquals("456@NEWexample2.com", u.getPersonal().getEmail()); - } else if (u.getBarcode().equals("789")) { - assertEquals("789@NEWexample3.com", u.getPersonal().getEmail()); - } - }); - mockMvc.perform(get(format(PREVIEW_USERS_URL_TEMPLATE, jobId)) - .headers(defaultHeaders()) - .queryParam(LIMIT, String.valueOf(10))) - .andExpect(status().isOk()) - .andReturn(); - } } private JobCommand createBulkEditJobRequest(UUID id, ExportType exportType, EntityType entityType, IdentifierType identifierType) { @@ -936,57 +205,4 @@ private JobCommand createBulkEditJobRequest(UUID id, ExportType exportType, Enti return jobCommand; } - private UserCollection buildUserCollection() { - return new UserCollection() - .addUsersItem(new User().barcode("123").patronGroup("3684a786-6671-4268-8ed0-9db82ebca60b")) - .addUsersItem(new User().barcode("456").patronGroup("3684a786-6671-4268-8ed0-9db82ebca60b")) - .addUsersItem(new User().barcode("789").patronGroup("3684a786-6671-4268-8ed0-9db82ebca60b")) - .totalRecords(3); - } - - private ItemCollection buildItemCollection() { - return new ItemCollection() - .addItemsItem(new Item().barcode("123")) - .addItemsItem(new Item().barcode("456")) - .addItemsItem(new Item().barcode("789")) - .totalRecords(3); - } - - private void verifyLocationUpdate(ItemCollection expectedItems, ItemCollection actualItems) { - assertThat(expectedItems.getItems(), hasSize(actualItems.getItems().size())); - for (int i = 0; i < expectedItems.getItems().size(); i++) { - assertThat(expectedItems.getItems().get(i).getId(), equalTo(actualItems.getItems().get(i).getId())); - assertThat(expectedItems.getItems().get(i).getPermanentLocation(), equalTo(actualItems.getItems().get(i).getPermanentLocation())); - assertThat(expectedItems.getItems().get(i).getTemporaryLocation(), equalTo(actualItems.getItems().get(i).getTemporaryLocation())); - assertThat(expectedItems.getItems().get(i).getEffectiveLocation(), equalTo(actualItems.getItems().get(i).getEffectiveLocation())); - } - } - - private void verifyLoanTypeUpdate(ItemCollection expectedItems, ItemCollection actualItems) { - assertThat(expectedItems.getItems(), hasSize(actualItems.getItems().size())); - for (int i = 0; i < expectedItems.getItems().size(); i++) { - assertThat(expectedItems.getItems().get(i).getId(), equalTo(actualItems.getItems().get(i).getId())); - assertThat(expectedItems.getItems().get(i).getPermanentLoanType(), equalTo(actualItems.getItems().get(i).getPermanentLoanType())); - assertThat(expectedItems.getItems().get(i).getTemporaryLoanType(), equalTo(actualItems.getItems().get(i).getTemporaryLoanType())); - } - } - - private String getIdentifier(IdentifierType identifierType) { - switch (identifierType) { - case ID: - return "b7a9718a-0c26-4d43-ace9-52234ff74ad8"; - case HRID: - return "it00000000002"; - case HOLDINGS_RECORD_ID: - return "4929e3d5-8de5-4bb2-8818-3c23695e7505"; - case BARCODE: - return "0001"; - case FORMER_IDS: - return "former_id"; - case ACCESSION_NUMBER: - return "accession_number"; - default: - return null; - } - } } diff --git a/src/test/java/org/folio/dew/controller/ItemsContentUpdateTestData.java b/src/test/java/org/folio/dew/controller/ItemsContentUpdateTestData.java deleted file mode 100644 index b4daf0324..000000000 --- a/src/test/java/org/folio/dew/controller/ItemsContentUpdateTestData.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.folio.dew.controller; - -import static org.folio.dew.domain.dto.ItemContentUpdate.ActionEnum.CLEAR_FIELD; -import static org.folio.dew.domain.dto.ItemContentUpdate.ActionEnum.REPLACE_WITH; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.PERMANENT_LOAN_TYPE; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.PERMANENT_LOCATION; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.STATUS; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.TEMPORARY_LOAN_TYPE; -import static org.folio.dew.domain.dto.ItemContentUpdate.OptionEnum.TEMPORARY_LOCATION; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.folio.dew.domain.dto.ItemContentUpdate; - -@AllArgsConstructor -@Getter -public enum ItemsContentUpdateTestData { - REPLACE_WITH_PERMANENT_LOCATION(PERMANENT_LOCATION, REPLACE_WITH, "Annex", - "src/test/resources/output/expected_items_with_updated_permanent_location.json", - "src/test/resources/output/expected_items_with_updated_permanent_location.csv", - "src/test/resources/output/expected_preview_items_with_updated_permanent_location.csv"), - REPLACE_WITH_TEMPORARY_LOCATION(TEMPORARY_LOCATION, REPLACE_WITH, "Annex", - "src/test/resources/output/expected_items_with_updated_temporary_location.json", - "src/test/resources/output/expected_items_with_updated_temporary_location.csv", - "src/test/resources/output/expected_preview_items_with_updated_temporary_location.csv"), - REPLACE_WITH_NULL_PERMANENT_LOCATION(PERMANENT_LOCATION, REPLACE_WITH, null, - "src/test/resources/output/expected_items_with_deleted_permanent_location.json", - "src/test/resources/output/expected_items_with_deleted_permanent_location.csv", - "src/test/resources/output/expected_preview_items_with_deleted_permanent_location.csv"), - REPLACE_WITH_NULL_TEMPORARY_LOCATION(TEMPORARY_LOCATION, REPLACE_WITH, null, - "src/test/resources/output/expected_items_with_deleted_temporary_location.json", - "src/test/resources/output/expected_items_with_deleted_temporary_location.csv", - "src/test/resources/output/expected_preview_items_with_deleted_temporary_location.csv"), - REPLACE_WITH_PERMANENT_LOAN_TYPE(PERMANENT_LOAN_TYPE, REPLACE_WITH, "Reading room", - "src/test/resources/output/expected_items_with_updated_permanent_loan_type.json", - "src/test/resources/output/expected_items_with_updated_permanent_loan_type.csv", - "src/test/resources/output/expected_items_with_updated_permanent_loan_type.csv"), - REPLACE_WITH_TEMPORARY_LOAN_TYPE(TEMPORARY_LOAN_TYPE, REPLACE_WITH, "Reading room", - "src/test/resources/output/expected_items_with_updated_temporary_loan_type.json", - "src/test/resources/output/expected_items_with_updated_temporary_loan_type.csv", - "src/test/resources/output/expected_items_with_updated_temporary_loan_type.csv"), - REPLACE_WITH_NULL_PERMANENT_LOAN_TYPE(PERMANENT_LOAN_TYPE, REPLACE_WITH, null, - "src/test/resources/output/expected_items_with_deleted_permanent_loan_type.json", - "src/test/resources/output/expected_items_with_deleted_permanent_loan_type.csv", - "src/test/resources/output/expected_preview_items_with_deleted_permanent_loan_type.csv"), - REPLACE_WITH_NULL_TEMPORARY_LOAN_TYPE(TEMPORARY_LOAN_TYPE, REPLACE_WITH, null, - "src/test/resources/output/expected_items_with_deleted_temporary_loan_type.json", - "src/test/resources/output/expected_items_with_deleted_temporary_loan_type.csv", - "src/test/resources/output/expected_preview_items_with_deleted_temporary_loan_type.csv"), - REPLACE_WITH_ALLOWED_STATUS(STATUS, REPLACE_WITH, "Missing", - "src/test/resources/output/expected_items_with_updated_status.json", - null, null), - REPLACE_WITH_NOT_ALLOWED_STATUS(STATUS, REPLACE_WITH, "Aged to lost", - "src/test/resources/output/expected_items_with_non_updated_status.json", - null, null), - REPLACE_WITH_EMPTY_STATUS(STATUS, REPLACE_WITH, null, - "src/test/resources/output/expected_items_with_non_updated_status.json", - null, null), - CLEAR_FIELD_PERMANENT_LOCATION(PERMANENT_LOCATION, CLEAR_FIELD, null, - "src/test/resources/output/expected_items_with_deleted_permanent_location.json", - "src/test/resources/output/expected_items_with_deleted_permanent_location.csv", - "src/test/resources/output/expected_preview_items_with_deleted_permanent_location.csv"), - CLEAR_FIELD_TEMPORARY_LOCATION(TEMPORARY_LOCATION, CLEAR_FIELD, null, - "src/test/resources/output/expected_items_with_deleted_temporary_location.json", - "src/test/resources/output/expected_items_with_deleted_temporary_location.csv", - "src/test/resources/output/expected_preview_items_with_deleted_temporary_location.csv"), - CLEAR_FIELD_STATUS(STATUS, CLEAR_FIELD, null, - "src/test/resources/output/expected_items_with_non_updated_status.json", - null, null), - CLEAR_FIELD_PERMANENT_LOAN_TYPE(PERMANENT_LOAN_TYPE, CLEAR_FIELD, null, - "src/test/resources/output/expected_items_with_deleted_permanent_loan_type.json", - "src/test/resources/output/expected_items_with_deleted_permanent_loan_type.csv", - "src/test/resources/output/expected_preview_items_with_deleted_permanent_loan_type.csv"), - CLEAR_FIELD_TEMPORARY_LOAN_TYPE(TEMPORARY_LOAN_TYPE, CLEAR_FIELD, null, - "src/test/resources/output/expected_items_with_deleted_temporary_loan_type.json", - "src/test/resources/output/expected_items_with_deleted_temporary_loan_type.csv", - "src/test/resources/output/expected_preview_items_with_deleted_temporary_loan_type.csv"); - - final ItemContentUpdate.OptionEnum option; - final ItemContentUpdate.ActionEnum action; - final String value; - final String expectedPreviewJsonPath; - final String expectedCsvPath; - final String expectedPreviewCsvPath; -} diff --git a/src/test/java/org/folio/dew/service/BulkEditParseServiceTest.java b/src/test/java/org/folio/dew/service/BulkEditParseServiceTest.java deleted file mode 100644 index feedbdef6..000000000 --- a/src/test/java/org/folio/dew/service/BulkEditParseServiceTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.folio.dew.service; - -import org.folio.dew.BaseBatchTest; -import org.folio.dew.domain.dto.*; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Collections; -import java.util.Set; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - -class BulkEditParseServiceTest extends BaseBatchTest { - @Autowired - private BulkEditParseService bulkEditParseService; - - @ParameterizedTest - @ValueSource(strings = {"", " "}) - void shouldIgnoreBlankBarcodeAndExternalSystemId(String val) { - var userFormat = UserFormat.builder() - .patronGroup("PatronGroup") - .externalSystemId(val) - .barcode(val) - .active("true") - .departments("") - .proxyFor("") - .addresses("") - .build(); - - assertThat(bulkEditParseService.mapUserFormatToUser(userFormat).getExternalSystemId()).isNull(); - assertThat(bulkEditParseService.mapUserFormatToUser(userFormat).getBarcode()).isNull(); - } - - @Test - void shouldReturnInitialIdsForWrongReferenceIdsWhenMappingToUser() { - var userFormat = UserFormat.builder() - .active("true") - .patronGroup("staff") - .addresses(";;;;;;;false;db541cda-fcc7-403b-8077-3613f3244901") - .preferredContactTypeId("002") - .departments("103aee0f-c5f6-44de-94aa-74093f0e45d9") - .build(); - - var expectedUser = new User() - .personal(new Personal().addresses(Collections.singletonList(new Address().addressTypeId("db541cda-fcc7-403b-8077-3613f3244901")))) - .patronGroup("3684a786-6671-4268-8ed0-9db82ebca60b") - .departments(Set.of(UUID.fromString("103aee0f-c5f6-44de-94aa-74093f0e45d9"))); - - var actualUser = bulkEditParseService.mapUserFormatToUser(userFormat); - - assertEquals(expectedUser.getPersonal().getAddresses().get(0).getAddressTypeId(), actualUser.getPersonal().getAddresses().get(0).getAddressTypeId()); - assertEquals(expectedUser.getDepartments(), actualUser.getDepartments()); - } -} diff --git a/src/test/java/org/folio/dew/service/BulkEditRollBackServiceTest.java b/src/test/java/org/folio/dew/service/BulkEditRollBackServiceTest.java deleted file mode 100644 index 12687e4a5..000000000 --- a/src/test/java/org/folio/dew/service/BulkEditRollBackServiceTest.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.folio.dew.service; - -import org.folio.dew.client.DataExportSpringClient; -import org.folio.dew.repository.RemoteFilesStorage; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.launch.JobOperator; - -import java.util.List; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class BulkEditRollBackServiceTest { - - @Mock - private JobOperator jobOperator; - @Mock - private BulkEditRollBackJobLauncher rollBackJobLauncher; - @Mock - private DataExportSpringClient dataExportSpringClient; - @Mock - private RemoteFilesStorage remoteFilesStorage; - - @InjectMocks - private BulkEditRollBackService bulkEditRollBackService; - - @Test - void stopAndRollBackJobExecutionByJobIdTest() throws Exception { - var jobId = UUID.fromString("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var jobIdWithRollBackFile = jobId.toString(); - var executionId = 0l; - var job = new org.folio.dew.domain.dto.Job(); - job.setFiles(List.of("minio/path/" + jobIdWithRollBackFile + "_file.csv")); - - bulkEditRollBackService.putExecutionInfoPerJob(executionId, jobId); - when(dataExportSpringClient.getJobById(isA(String.class))).thenReturn(job); - doNothing().when(remoteFilesStorage).downloadObject(isA(String.class), isA(String.class)); - when(rollBackJobLauncher.run(any(), isA(JobParameters.class))).thenReturn(new JobExecution(1l)); - - bulkEditRollBackService.stopAndRollBackJobExecutionByJobId(jobId); - - verify(jobOperator, times(1)).stop(executionId); - verify(dataExportSpringClient, times(1)).getJobById(jobIdWithRollBackFile); - verify(remoteFilesStorage, times(1)).downloadObject(isA(String.class), isA(String.class)); - verify(rollBackJobLauncher, times(1)).run(any(), isA(JobParameters.class)); - } - - @Test - void getFileForRollBackFromMinIO() { - var jobIdWithRollBackFile = "74914e57-3406-4757-938b-9a3f718d0ee6"; - var fileUploadName = "/some/file/" + jobIdWithRollBackFile + "_file.csv"; - var job = new org.folio.dew.domain.dto.Job(); - job.setFiles(List.of("minio/path/" + jobIdWithRollBackFile + "_file.csv")); - - when(dataExportSpringClient.getJobById(isA(String.class))).thenReturn(job); - - var actual = bulkEditRollBackService.getFileForRollBackFromMinIO(fileUploadName); - assertEquals("minio/path/74914e57-3406-4757-938b-9a3f718d0ee6_file.csv", actual); - } - - @Test - void cleanJobDataTest() { - var jobId = UUID.fromString("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var jobIdWithRollBackFile = "74914e57-3406-4757-938b-9a3f718d0ee6"; - var executionId = 0l; - var userId = "userId"; - - bulkEditRollBackService.putExecutionInfoPerJob(executionId, jobId); - bulkEditRollBackService.putUserIdForJob(userId, jobId); - assertTrue(bulkEditRollBackService.isExecutionIdExistForJob(jobId)); - assertTrue(bulkEditRollBackService.isUserBeRollBack(userId, jobId)); - - bulkEditRollBackService.cleanJobData(jobId); - assertFalse(bulkEditRollBackService.isExecutionIdExistForJob(jobId)); - assertTrue(bulkEditRollBackService.isUserBeRollBack(userId, jobId)); - } - - @Test - void cleanJobDataWithCompletedExitCodeTest() { - var jobId = UUID.fromString("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var jobIdWithRollBackFile = "74914e57-3406-4757-938b-9a3f718d0ee6"; - var executionId = 0l; - var userId = "userId"; - - bulkEditRollBackService.putExecutionInfoPerJob(executionId, jobId); - bulkEditRollBackService.putUserIdForJob(userId, jobId); - assertTrue(bulkEditRollBackService.isExecutionIdExistForJob(jobId)); - assertTrue(bulkEditRollBackService.isUserBeRollBack(userId, jobId)); - - bulkEditRollBackService.cleanJobData(ExitStatus.COMPLETED.getExitCode(), jobId); - assertFalse(bulkEditRollBackService.isExecutionIdExistForJob(jobId)); - assertTrue(bulkEditRollBackService.isUserBeRollBack(userId, jobId)); - } - - @Test - void cleanJobDataWithStoppedExitCodeTest() { - var jobId = UUID.fromString("edd30136-9a7b-4226-9e82-83024dbeac4a"); - var jobIdWithRollBackFile = "74914e57-3406-4757-938b-9a3f718d0ee6"; - var executionId = 0l; - var userId = "userId"; - - bulkEditRollBackService.putExecutionInfoPerJob(executionId, jobId); - bulkEditRollBackService.putUserIdForJob(userId, jobId); - assertTrue(bulkEditRollBackService.isExecutionIdExistForJob(jobId)); - - bulkEditRollBackService.cleanJobData(ExitStatus.STOPPED.getExitCode(), jobId); - assertTrue(bulkEditRollBackService.isExecutionIdExistForJob(jobId)); - assertTrue(bulkEditRollBackService.isUserBeRollBack(userId, jobId)); - assertFalse(bulkEditRollBackService.isUserBeRollBack(userId, jobId)); - } -} diff --git a/src/test/java/org/folio/dew/service/BulkEditUserContentUpdateServiceTest.java b/src/test/java/org/folio/dew/service/BulkEditUserContentUpdateServiceTest.java deleted file mode 100644 index 1c0b8b40f..000000000 --- a/src/test/java/org/folio/dew/service/BulkEditUserContentUpdateServiceTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.folio.dew.service; - -import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_IDENTIFIERS; -import static org.folio.dew.domain.dto.ExportType.BULK_EDIT_UPDATE; -import static org.folio.dew.domain.dto.JobParameterNames.PREVIEW_FILE_NAME; -import static org.folio.dew.domain.dto.JobParameterNames.TEMP_OUTPUT_FILE_PATH; -import static org.folio.dew.domain.dto.JobParameterNames.UPDATED_FILE_NAME; -import static org.folio.dew.utils.Constants.CSV_EXTENSION; -import static org.folio.dew.utils.Constants.PATH_SEPARATOR; -import static org.folio.dew.utils.Constants.PREVIEW_PREFIX; -import static org.folio.dew.utils.Constants.UPDATED_PREFIX; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; - -import lombok.SneakyThrows; -import org.apache.commons.io.FilenameUtils; -import org.folio.de.entity.JobCommand; -import org.folio.dew.BaseBatchTest; -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateAction; -import org.folio.dew.domain.dto.UserContentUpdateCollection; -import org.folio.dew.service.update.BulkEditUserContentUpdateService; -import org.junit.jupiter.api.Test; -import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Collections; -import java.util.UUID; - -class BulkEditUserContentUpdateServiceTest extends BaseBatchTest { - private static final String USER_DATA = "src/test/resources/upload/user_data.csv"; - - @Autowired - private BulkEditUserContentUpdateService contentUpdateService; - - @Test - @SneakyThrows - void shouldCreateUpdatedAndPreviewFilesAndUpdateJobCommand() { - var jobId = UUID.randomUUID(); - var uploadedFileName = FilenameUtils.getName(USER_DATA); - var updatedFileName = jobId + PATH_SEPARATOR + UPDATED_PREFIX + uploadedFileName; - var previewFileName = jobId + PATH_SEPARATOR + PREVIEW_PREFIX + uploadedFileName; - remoteFilesStorage.upload(jobId + PATH_SEPARATOR + uploadedFileName, USER_DATA); - - var jobCommand = new JobCommand(); - jobCommand.setId(jobId); - jobCommand.setExportType(BULK_EDIT_IDENTIFIERS); - jobCommand.setJobParameters(new JobParametersBuilder() - .addString(TEMP_OUTPUT_FILE_PATH, "test/path/" + USER_DATA.replace(CSV_EXTENSION, EMPTY)) - .toJobParameters()); - - jobCommandsReceiverService.addBulkEditJobCommand(jobCommand); - - var contentUpdates = new UserContentUpdateCollection() - .userContentUpdates(Collections.singletonList(new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.PATRON_GROUP) - .actions(Collections.singletonList(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value("PatronGroup"))))) - .totalRecords(1); - - var res = contentUpdateService.process(jobCommand, contentUpdates); - - assertThat(res.getEntitiesForPreview(), hasSize(2)); - assertThat(res.getEntitiesForPreview().stream().allMatch(userFormat -> "PatronGroup".equals(userFormat.getPatronGroup())), is(true)); - - assertThat(remoteFilesStorage.containsFile(updatedFileName), is(true)); - assertThat(remoteFilesStorage.containsFile(previewFileName), is(true)); - - assertThat(jobCommand.getExportType(), equalTo(BULK_EDIT_UPDATE)); - assertThat(jobCommand.getJobParameters().getString(UPDATED_FILE_NAME), equalTo(updatedFileName)); - assertThat(jobCommand.getJobParameters().getString(PREVIEW_FILE_NAME), equalTo(previewFileName)); - } -} diff --git a/src/test/java/org/folio/dew/service/update/EmailUpdateStrategyTest.java b/src/test/java/org/folio/dew/service/update/EmailUpdateStrategyTest.java deleted file mode 100644 index 4172a8270..000000000 --- a/src/test/java/org/folio/dew/service/update/EmailUpdateStrategyTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.folio.dew.service.update; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateAction; -import org.folio.dew.domain.dto.UserFormat; -import org.folio.dew.error.BulkEditException; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.ValueSource; - -import java.util.List; - -class EmailUpdateStrategyTest { - private final EmailUpdateStrategy updateStrategy = new EmailUpdateStrategy(); - - @Test - void shouldUpdateEmailIfDomainMatch() { - var userFormat = new UserFormat().withEmail("test@somedomain.com"); - var contentUpdate = new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EMAIL_ADDRESS) - .actions(List.of(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.FIND) - .value("somedomain.com"), - new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value("newdomain.com") - )); - - var updatedUserFormat = updateStrategy.applyUpdate(userFormat, contentUpdate); - - assertThat(updatedUserFormat.getEmail(), equalTo("test@newdomain.com")); - } - - @ParameterizedTest - @CsvSource({"test,org@somedomain.com", "te,orgst@somedomain.com", "st,teorg@somedomain.com", "es,torgt@somedomain.com", - "@,testorgsomedomain.com", "t@,tesorgsomedomain.com", "@s,testorgomedomain.com", "some,test@orgdomain.com", - "med,test@soorgomain.com", "e,torgst@somorgdomain.com", ".com,test@somedomainorg", ".,test@somedomainorgcom", - "o,test@sorgmedorgmain.corgm", "co,test@somedomain.orgm", "om,test@sorgedorgain.corg"}) - void shouldUpdateAnyPartOfEmail(String findValue, String expected) { - var userFormat = new UserFormat().withEmail("test@somedomain.com"); - var contentUpdate = new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EMAIL_ADDRESS) - .actions(List.of(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.FIND) - .value(findValue), - new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value("org") - )); - - var updatedUserFormat = updateStrategy.applyUpdate(userFormat, contentUpdate); - - assertThat(updatedUserFormat.getEmail(), equalTo(expected)); - } - - @ParameterizedTest - @ValueSource(strings = {"another.com", "SomeDomain.com"}) - void shouldThrowExceptionIfDomainDoesNotMatch(String findValue) { - var userFormat = new UserFormat().withEmail("test@somedomain.com"); - var contentUpdate = new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EMAIL_ADDRESS) - .actions(List.of(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.FIND) - .value(findValue), - new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value("newdomain.com") - )); - - assertThrows(BulkEditException.class, () -> updateStrategy.applyUpdate(userFormat, contentUpdate)); - } -} diff --git a/src/test/java/org/folio/dew/service/update/ExpirationDateUpdateStrategyTest.java b/src/test/java/org/folio/dew/service/update/ExpirationDateUpdateStrategyTest.java deleted file mode 100644 index c9426a826..000000000 --- a/src/test/java/org/folio/dew/service/update/ExpirationDateUpdateStrategyTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.folio.dew.service.update; - -import static java.time.ZoneOffset.UTC; -import static org.folio.dew.utils.BulkEditProcessorHelper.dateToString; -import static org.folio.dew.utils.Constants.DATE_TIME_PATTERN; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateAction; -import org.folio.dew.domain.dto.UserFormat; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.Date; - -class ExpirationDateUpdateStrategyTest { - private final static String CURRENT_DATE = dateToString(new Date()); - private final ExpirationDateUpdateStrategy updateStrategy = new ExpirationDateUpdateStrategy(); - - @ParameterizedTest - @ValueSource(booleans = {true, false}) - void shouldUpdateExpirationDateAndActiveValue(boolean isActive) { - var userFormat = new UserFormat().withExpirationDate(CURRENT_DATE); - var newDate = isActive ? - dateToString(Date.from(LocalDateTime.now().plusDays(1).atZone(UTC).toInstant())) : - dateToString(Date.from(LocalDateTime.now().minusDays(1).atZone(UTC).toInstant())); - var contentUpdate = new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EXPIRATION_DATE) - .actions(Collections.singletonList(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value(newDate))); - var updatedUserFormat = updateStrategy.applyUpdate(userFormat, contentUpdate); - - assertThat(updatedUserFormat.getExpirationDate(), equalTo(newDate)); - assertThat(updatedUserFormat.getActive(), equalTo(Boolean.toString(isActive))); - } - - @Test - void shouldNotUpdateExpirationDateIfValuesAreEqual() { - var userFormat = new UserFormat().withActive("false").withExpirationDate(CURRENT_DATE); - var contentUpdate = new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.EXPIRATION_DATE) - .actions(Collections.singletonList(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value(CURRENT_DATE))); - - assertThat(userFormat, equalTo(updateStrategy.applyUpdate(userFormat, contentUpdate))); - } -} diff --git a/src/test/java/org/folio/dew/service/update/PatronGroupUpdateStrategyTest.java b/src/test/java/org/folio/dew/service/update/PatronGroupUpdateStrategyTest.java deleted file mode 100644 index e1da22c60..000000000 --- a/src/test/java/org/folio/dew/service/update/PatronGroupUpdateStrategyTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.folio.dew.service.update; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateAction; -import org.folio.dew.domain.dto.UserFormat; -import org.junit.jupiter.api.Test; - -import java.util.Collections; - -class PatronGroupUpdateStrategyTest { - private final static String NEW_VALUE = "New patron group"; - private final PatronGroupUpdateStrategy updateStrategy = new PatronGroupUpdateStrategy(); - - @Test - void shouldUpdatePatronGroup() { - var userFormat = new UserFormat().withPatronGroup("Patron group"); - var contentUpdate = new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.PATRON_GROUP) - .actions(Collections.singletonList(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value(NEW_VALUE))); - - var updatedUserFormat = updateStrategy.applyUpdate(userFormat, contentUpdate); - - assertThat(updatedUserFormat.getPatronGroup(), equalTo(NEW_VALUE)); - } - - @Test - void shouldNotUpdatePatronGroupIfValuesAreEqual() { - var userFormat = new UserFormat().withPatronGroup(NEW_VALUE); - var contentUpdate = new UserContentUpdate() - .option(UserContentUpdate.OptionEnum.PATRON_GROUP) - .actions(Collections.singletonList(new UserContentUpdateAction() - .name(UserContentUpdateAction.NameEnum.REPLACE_WITH) - .value(NEW_VALUE))); - - assertThat(userFormat, equalTo(updateStrategy.applyUpdate(userFormat, contentUpdate))); - } -} diff --git a/src/test/java/org/folio/dew/service/validation/HoldingsContentUpdateValidatorServiceTest.java b/src/test/java/org/folio/dew/service/validation/HoldingsContentUpdateValidatorServiceTest.java deleted file mode 100644 index dfa309ff1..000000000 --- a/src/test/java/org/folio/dew/service/validation/HoldingsContentUpdateValidatorServiceTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.folio.dew.service.validation; - -import static org.folio.dew.domain.dto.HoldingsContentUpdate.ActionEnum.CLEAR_FIELD; -import static org.folio.dew.domain.dto.HoldingsContentUpdate.ActionEnum.REPLACE_WITH; -import static org.folio.dew.domain.dto.HoldingsContentUpdate.OptionEnum.PERMANENT_LOCATION; -import static org.folio.dew.domain.dto.HoldingsContentUpdate.OptionEnum.TEMPORARY_LOCATION; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.folio.dew.BaseBatchTest; -import org.folio.dew.domain.dto.HoldingsContentUpdate; -import org.folio.dew.domain.dto.HoldingsContentUpdateCollection; -import org.folio.dew.error.ContentUpdateValidationException; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Collections; -import java.util.List; - -class HoldingsContentUpdateValidatorServiceTest extends BaseBatchTest { - @Autowired - private HoldingsContentUpdateValidatorService validatorService; - - @ParameterizedTest - @EnumSource(HoldingsContentUpdateValidTestData.class) - void shouldAllowValidContentUpdateData(HoldingsContentUpdateValidTestData testData) { - assertTrue(validatorService.validateContentUpdateCollection(testData.getUpdateCollection())); - } - - @ParameterizedTest - @EnumSource(HoldingsContentUpdateInvalidTestData.class) - void shouldRejectInvalidContentUpdateData(HoldingsContentUpdateInvalidTestData testData) { - var updates = testData.getUpdateCollection(); - assertThrows(ContentUpdateValidationException.class, () -> validatorService.validateContentUpdateCollection(updates)); - } - - @AllArgsConstructor - @Getter - enum HoldingsContentUpdateValidTestData { - REPLACE_WITH_PERMANENT_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(Collections.singletonList(new HoldingsContentUpdate() - .option(PERMANENT_LOCATION) - .action(REPLACE_WITH) - .value("Annex"))) - .totalRecords(1)), - REPLACE_WITH_TEMPORARY_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(Collections.singletonList(new HoldingsContentUpdate() - .option(TEMPORARY_LOCATION) - .action(REPLACE_WITH) - .value("Annex"))) - .totalRecords(1)), - CLEAR_FIELD_TEMPORARY_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(Collections.singletonList(new HoldingsContentUpdate() - .option(TEMPORARY_LOCATION) - .action(CLEAR_FIELD))) - .totalRecords(1)), - REPLACE_PERMANENT_LOCATION_CLEAR_TEMPORARY_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(List.of(new HoldingsContentUpdate() - .option(PERMANENT_LOCATION) - .action(REPLACE_WITH) - .value("Annex"), - new HoldingsContentUpdate() - .option(TEMPORARY_LOCATION) - .action(CLEAR_FIELD))) - .totalRecords(2)); - - final HoldingsContentUpdateCollection updateCollection; - } - - @AllArgsConstructor - @Getter - enum HoldingsContentUpdateInvalidTestData { - REPLACE_WITH_NON_EXISTING_PERMANENT_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(Collections.singletonList(new HoldingsContentUpdate() - .option(PERMANENT_LOCATION) - .action(REPLACE_WITH) - .value("Abc"))) - .totalRecords(1)), - REPLACE_WITH_NON_EXISTING_TEMPORARY_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(Collections.singletonList(new HoldingsContentUpdate() - .option(TEMPORARY_LOCATION) - .action(REPLACE_WITH) - .value("Abc"))) - .totalRecords(1)), - CLEAR_FIELD_PERMANENT_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(Collections.singletonList(new HoldingsContentUpdate() - .option(PERMANENT_LOCATION) - .action(CLEAR_FIELD))) - .totalRecords(1)), - REPLACE_TEMPORARY_LOCATION_CLEAR_PERMANENT_LOCATION(new HoldingsContentUpdateCollection() - .holdingsContentUpdates(List.of(new HoldingsContentUpdate() - .option(TEMPORARY_LOCATION) - .action(REPLACE_WITH) - .value("Annex"), - new HoldingsContentUpdate() - .option(PERMANENT_LOCATION) - .action(CLEAR_FIELD))) - .totalRecords(2)); - - final HoldingsContentUpdateCollection updateCollection; - } -} - - diff --git a/src/test/java/org/folio/dew/service/validation/UserContentUpdateInvalidTestData.java b/src/test/java/org/folio/dew/service/validation/UserContentUpdateInvalidTestData.java deleted file mode 100644 index 239ed8242..000000000 --- a/src/test/java/org/folio/dew/service/validation/UserContentUpdateInvalidTestData.java +++ /dev/null @@ -1,192 +0,0 @@ -package org.folio.dew.service.validation; - -import static org.folio.dew.domain.dto.UserContentUpdate.OptionEnum.EMAIL_ADDRESS; -import static org.folio.dew.domain.dto.UserContentUpdate.OptionEnum.EXPIRATION_DATE; -import static org.folio.dew.domain.dto.UserContentUpdate.OptionEnum.PATRON_GROUP; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.ADD_TO_EXISTING; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.CLEAR_FIELD; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.FIND; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.FIND_AND_REMOVE_THESE; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.REPLACE_WITH; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateAction; - -import java.util.Collections; -import java.util.List; - -public enum UserContentUpdateInvalidTestData { - PATRON_GROUP_REPLACE_WITH_EMPTY_VALUE( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(REPLACE_WITH)))), - PATRON_GROUP_REPLACE_WITH_NON_EXISTING_VALUE( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("non-existing group") - )) - ), - PATRON_GROUP_CLEAR_FIELD( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(CLEAR_FIELD)))), - PATRON_GROUP_FIND( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(FIND) - .value("find value")))), - PATRON_GROUP_FIND_AND_REPLACE_WITH( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(List.of( - new UserContentUpdateAction() - .name(FIND) - .value("find value"), - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("new value")))), - PATRON_GROUP_ADD_TO_EXISTING( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(ADD_TO_EXISTING) - .value("find value")))), - PATRON_GROUP_FIND_AND_REMOVE_THESE( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(FIND_AND_REMOVE_THESE) - .value("find value")))), - EXPIRATION_DATE_REPLACE_WITH_INVALID_DATE( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("2022/01/01")))), - EXPIRATION_DATE_REPLACE_WITH_EMPTY_VALUE( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(REPLACE_WITH)))), - EXPIRATION_DATE_CLEAR_FIELD( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(CLEAR_FIELD)))), - EXPIRATION_DATE_FIND( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(FIND) - .value("find value")))), - EXPIRATION_DATE_FIND_AND_REPLACE_WITH( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(List.of( - new UserContentUpdateAction() - .name(FIND) - .value("find value"), - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("new value")))), - EXPIRATION_DATE_ADD_TO_EXISTING( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(ADD_TO_EXISTING) - .value("find value")))), - EXPIRATION_DATE_AND_REMOVE_THESE( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(FIND_AND_REMOVE_THESE) - .value("find value")))), - EMAIL_REPLACE_WITH_EMPTY_VALUE( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(REPLACE_WITH)))), - EMAIL_CLEAR_FIELD( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(CLEAR_FIELD)))), - EMAIL_FIND( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(FIND) - .value("find value")))), - EMAIL_ADD_TO_EXISTING( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(ADD_TO_EXISTING) - .value("find value")))), - EMAIL_FIND_AND_REMOVE_THESE( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(FIND_AND_REMOVE_THESE) - .value("find value")))), - EMAIL_FIND_AND_AND_REPLACE_WITH_EMPTY_FIND( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(List.of( - new UserContentUpdateAction() - .name(FIND), - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("replace value")))), - EMAIL_FIND_AND_AND_REPLACE_WITH_EMPTY_REPLACE( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(List.of( - new UserContentUpdateAction() - .name(FIND) - .value("find value"), - new UserContentUpdateAction() - .name(REPLACE_WITH)))), - EMAIL_FIND_AND_AND_REPLACE_WITH_EQUAL_VALUES( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(List.of( - new UserContentUpdateAction() - .name(FIND) - .value("some value"), - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("some value")))); - - private UserContentUpdate update; - - UserContentUpdateInvalidTestData(UserContentUpdate update) { - this.update = update; - } - - public UserContentUpdate getUpdate() { - return update; - } -} diff --git a/src/test/java/org/folio/dew/service/validation/UserContentUpdateValidTestData.java b/src/test/java/org/folio/dew/service/validation/UserContentUpdateValidTestData.java deleted file mode 100644 index aa8de6c88..000000000 --- a/src/test/java/org/folio/dew/service/validation/UserContentUpdateValidTestData.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.folio.dew.service.validation; - -import static org.folio.dew.domain.dto.UserContentUpdate.OptionEnum.EMAIL_ADDRESS; -import static org.folio.dew.domain.dto.UserContentUpdate.OptionEnum.EXPIRATION_DATE; -import static org.folio.dew.domain.dto.UserContentUpdate.OptionEnum.PATRON_GROUP; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.CLEAR_FIELD; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.FIND; -import static org.folio.dew.domain.dto.UserContentUpdateAction.NameEnum.REPLACE_WITH; - -import org.folio.dew.domain.dto.UserContentUpdate; -import org.folio.dew.domain.dto.UserContentUpdateAction; - -import java.util.Collections; -import java.util.List; - -public enum UserContentUpdateValidTestData { - EXPIRATION_DATE_REPLACE_WITH( - new UserContentUpdate() - .option(EXPIRATION_DATE) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("2022-01-01 12:00:00.123Z")))), - PATRON_GROUP_REPLACE_WITH( - new UserContentUpdate() - .option(PATRON_GROUP) - .actions(Collections.singletonList( - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("PatronGroup")))), - EMAIL_FIND_AND_REPLACE_WITH( - new UserContentUpdate() - .option(EMAIL_ADDRESS) - .actions(List.of( - new UserContentUpdateAction() - .name(FIND) - .value("find value"), - new UserContentUpdateAction() - .name(REPLACE_WITH) - .value("new value")))); - - private UserContentUpdate update; - - UserContentUpdateValidTestData(UserContentUpdate update) { - this.update = update; - } - - public UserContentUpdate getUpdate() { - return update; - } -} diff --git a/src/test/java/org/folio/dew/service/validation/UserContentUpdateValidatorServiceTest.java b/src/test/java/org/folio/dew/service/validation/UserContentUpdateValidatorServiceTest.java deleted file mode 100644 index 3d0e68c43..000000000 --- a/src/test/java/org/folio/dew/service/validation/UserContentUpdateValidatorServiceTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.folio.dew.service.validation; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.Collections; -import org.folio.dew.BaseBatchTest; -import org.folio.dew.domain.dto.UserContentUpdateCollection; -import org.folio.dew.error.ContentUpdateValidationException; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.springframework.beans.factory.annotation.Autowired; - -class UserContentUpdateValidatorServiceTest extends BaseBatchTest { - @Autowired - private UserContentUpdateValidatorService validatorService; - @ParameterizedTest - @EnumSource(UserContentUpdateValidTestData.class) - void shouldAllowValidContentUpdates(UserContentUpdateValidTestData update) { - var updateCollection = new UserContentUpdateCollection() - .userContentUpdates(Collections.singletonList(update.getUpdate())) - .totalRecords(1); - - assertThat(validatorService.validateContentUpdateCollection(updateCollection), is(true)); - } - - @ParameterizedTest - @EnumSource(UserContentUpdateInvalidTestData.class) - void shouldRejectInvalidContentUpdates(UserContentUpdateInvalidTestData update) { - var updateCollection = new UserContentUpdateCollection() - .userContentUpdates(Collections.singletonList(update.getUpdate())) - .totalRecords(1); - - assertThrows(ContentUpdateValidationException.class, () -> validatorService.validateContentUpdateCollection(updateCollection)); - } -}