Skip to content

Commit

Permalink
MODEXPW-489 (#562)
Browse files Browse the repository at this point in the history
  • Loading branch information
siarhei-charniak authored Aug 16, 2024
1 parent b38fa56 commit a4f5cef
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
14 changes: 13 additions & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@
"inventory-storage.holdings.item.put"
]
},
{
"methods": [ "GET" ],
"pathPattern": "/bulk-edit/{jobId}/errors",
"permissionsRequired": [ "bulk-edit.errors.collection.get" ],
"modulePermissions": []
},
{
"methods": [ "GET" ],
"pathPattern": "/refresh-presigned-url",
Expand Down Expand Up @@ -327,6 +333,11 @@
"displayName": "start update items",
"description": "Start update items"
},
{
"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",
Expand All @@ -338,7 +349,8 @@
"description" : "All permissions for bulk-edit module",
"subPermissions" : [
"bulk-edit.item.post",
"bulk-edit.start.item.post"
"bulk-edit.start.item.post",
"bulk-edit.errors.collection.get"
]
},
{
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/folio/dew/controller/BulkEditController.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,26 @@
import static org.folio.dew.utils.SystemHelper.getTempDirWithSeparatorSuffix;
import static org.folio.spring.scope.FolioExecutionScopeExecutionContextManager.getRunnableWithCurrentFolioContext;

import io.swagger.annotations.ApiParam;
import jakarta.annotation.PostConstruct;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.FilenameUtils;
import org.folio.de.entity.JobCommand;
import org.folio.dew.batch.ExportJobManagerSync;
import org.folio.dew.domain.dto.Errors;
import org.folio.dew.error.NotFoundException;
import org.folio.dew.repository.LocalFilesStorage;
import org.folio.dew.service.BulkEditProcessingErrorsService;
import org.folio.dew.service.JobCommandsReceiverService;
import org.folio.spring.FolioExecutionContext;
import org.folio.spring.FolioModuleMetadata;
Expand All @@ -47,7 +53,9 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
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;

Expand All @@ -65,6 +73,7 @@ public class BulkEditController implements JobIdApi {
private final ExportJobManagerSync exportJobManagerSync;
private final List<Job> jobs;
private final LocalFilesStorage localFilesStorage;
private final BulkEditProcessingErrorsService bulkEditProcessingErrorsService;
private final FolioModuleMetadata folioModuleMetadata;
private final FolioExecutionContext folioExecutionContext;

Expand Down Expand Up @@ -152,6 +161,16 @@ public ResponseEntity<String> startJob(UUID jobId) {
return new ResponseEntity<>(HttpStatus.OK);
}

@Override
public ResponseEntity<Errors> 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);
}

private Job getBulkEditJob(JobCommand jobCommand) {
var jobName = BULK_EDIT_IDENTIFIERS == jobCommand.getExportType() ?
jobCommand.getExportType().getValue() + "-" + jobCommand.getEntityType() :
Expand Down
40 changes: 40 additions & 0 deletions src/main/resources/swagger.api/bulk-edit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,46 @@ paths:
$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
components:
schemas:
UUID:
Expand Down
77 changes: 77 additions & 0 deletions src/test/java/org/folio/dew/controller/BulkEditControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@
import static org.folio.dew.utils.Constants.FILE_NAME;
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.is;
import static org.hamcrest.Matchers.hasSize;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
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.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.io.FileInputStream;
Expand All @@ -34,13 +39,16 @@
import org.folio.dew.BaseBatchTest;
import org.folio.dew.client.UserClient;
import org.folio.dew.domain.dto.EntityType;
import org.folio.dew.domain.dto.Errors;
import org.folio.dew.domain.dto.ExportType;
import org.folio.dew.domain.dto.IdentifierType;
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.error.BulkEditException;
import org.folio.dew.error.FileOperationException;
import org.folio.dew.repository.LocalFilesStorage;
import org.folio.dew.service.BulkEditProcessingErrorsService;
import org.folio.dew.service.JobCommandsReceiverService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -51,9 +59,11 @@
import org.springframework.mock.web.MockMultipartFile;

class BulkEditControllerTest extends BaseBatchTest {
private static final String ERRORS_URL_TEMPLATE = "/bulk-edit/%s/errors";
private static final String UPLOAD_URL_TEMPLATE = "/bulk-edit/%s/upload";
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";
public static final String LIMIT = "limit";
private static final UUID JOB_ID = UUID.randomUUID();

@MockBean
Expand All @@ -65,6 +75,73 @@ class BulkEditControllerTest extends BaseBatchTest {
@Autowired
private LocalFilesStorage localFilesStorage;

@Autowired
private BulkEditProcessingErrorsService bulkEditProcessingErrorsService;

@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 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));
}

@Test
@DisplayName("Launch job on upload file with identifiers successfully")
@SneakyThrows
Expand Down

0 comments on commit a4f5cef

Please sign in to comment.