diff --git a/src/main/java/org/breedinginsight/api/v1/controller/geno/SampleSubmissionController.java b/src/main/java/org/breedinginsight/api/v1/controller/geno/SampleSubmissionController.java index 741d533a5..b62807645 100644 --- a/src/main/java/org/breedinginsight/api/v1/controller/geno/SampleSubmissionController.java +++ b/src/main/java/org/breedinginsight/api/v1/controller/geno/SampleSubmissionController.java @@ -188,6 +188,33 @@ public HttpResponse generateDArTFile(@PathVariable UUID programId, } } + @Get("/programs/{programId}/submissions/{submissionId}/export") + @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.PROGRAM_SCOPED_ROLES}) + @Produces(value={"text/csv", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/octet-stream"}) + public HttpResponse sampleSubmissionExport(@PathVariable UUID programId, @PathVariable UUID submissionId) { + try { + Optional program = programService.getById(programId); + if(program.isEmpty()) { + return HttpResponse.notFound(); + } + Optional downloadFile = sampleSubmissionService.exportSubmission(program.get(), submissionId); + if(downloadFile.isEmpty()) { + return HttpResponse.notFound(); + } + HttpResponse response = HttpResponse + .ok(downloadFile.get().getStreamedFile()) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + downloadFile.get().getFileName()); + return response; + } catch (ApiException e) { + log.error(Utilities.generateApiExceptionLogMessage(e), e); + return HttpResponse.serverError(); + } catch (IOException e) { + log.error("Error exporting Sample Submission file", e); + HttpResponse response = HttpResponse.status(HttpStatus.INTERNAL_SERVER_ERROR, "Error exporting Sample Submission file").contentType(MediaType.TEXT_PLAIN).body("Error exporting Sample Submission file"); + return response; + } + } + @Get("/programs/{programId}/submissions/{submissionId}/lookup") @ProgramSecured(roleGroups = {ProgramSecuredRoleGroup.PROGRAM_SCOPED_ROLES}) @Produces(value={"text/csv", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/octet-stream"}) diff --git a/src/main/java/org/breedinginsight/services/SampleSubmissionService.java b/src/main/java/org/breedinginsight/services/SampleSubmissionService.java index 496657a8c..667f3d4d1 100644 --- a/src/main/java/org/breedinginsight/services/SampleSubmissionService.java +++ b/src/main/java/org/breedinginsight/services/SampleSubmissionService.java @@ -65,6 +65,7 @@ public class SampleSubmissionService { private static final String COLUMN_GENOTYPE = "Genotype"; + public static final String COLUMN_SAMPLE_NAME = "Sample Name"; private static final String VENDOR_NOT_SUBMITTED_STATUS = "NOT SUBMITTED"; private static final String VENDOR_SUBMITTED_STATUS = "SUBMITTED"; private final String referenceSource; @@ -214,20 +215,71 @@ public Optional generateDArTFile(Program program, UUID submissionI columns.add(Column.builder().value(SampleSubmissionImport.Columns.TISSUE).dataType(Column.ColumnDataType.STRING).build()); columns.add(Column.builder().value(SampleSubmissionImport.Columns.COMMENTS).dataType(Column.ColumnDataType.STRING).build()); - //Sort samples first. May be updated to use BrAPI server sorting after cache removal changes are merged - submission.get().getSamples().sort(Comparator.comparing(BrAPISample::getPlateName) + sortSamples(submission.get().getSamples()); + + List> rows = new ArrayList<>(); + submission.get().getSamples().forEach(sample -> { + Map row = new HashMap<>(); + row.put(SampleSubmissionImport.Columns.PLATE_ID, sample.getPlateName()); + row.put(SampleSubmissionImport.Columns.ROW, sample.getRow()); + row.put(SampleSubmissionImport.Columns.COLUMN, sample.getColumn()); + row.put(SampleSubmissionImport.Columns.ORGANISM, sample.getAdditionalInfo().get(BrAPIAdditionalInfoFields.SAMPLE_ORGANISM).getAsString()); + row.put(SampleSubmissionImport.Columns.SPECIES, sample.getAdditionalInfo().has(BrAPIAdditionalInfoFields.SAMPLE_SPECIES) ? sample.getAdditionalInfo().get(BrAPIAdditionalInfoFields.SAMPLE_SPECIES).getAsString() : ""); + row.put(COLUMN_GENOTYPE, sample.getSampleName()); + row.put(SampleSubmissionImport.Columns.TISSUE, sample.getTissueType()); + row.put(SampleSubmissionImport.Columns.COMMENTS, sample.getSampleDescription()); + + rows.add(row); + }); + + + return Optional.of(new DownloadFile(filename, FileUtil.writeToStreamedFile(columns, rows, FileType.CSV, "Data"))); + } + + //Helper method to sort samples. May be updated to use BrAPI server sorting after cache removal changes are merged + public void sortSamples(List samples) { + samples.sort(Comparator.comparing(BrAPISample::getPlateName) .thenComparing(BrAPISample::getColumn) .thenComparing(BrAPISample::getRow)); + } + + public Optional exportSubmission(Program program, UUID submissionId) throws ApiException, IOException { + Optional submission = getSampleSubmission(program, submissionId, true); + if (submission.isEmpty()) { + return Optional.empty(); + } + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_hh-mm-ssZ"); + String timestamp = formatter.format(OffsetDateTime.now()); + String filename = Utilities.makePortableFilename(String.format("%s_SampleSubmission_%s.csv", submission.get().getName(), timestamp)); + + List columns = new ArrayList<>(); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.GERMPLASM_NAME).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.GERMPLASM_GID).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.OBS_UNIT_ID).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(COLUMN_SAMPLE_NAME).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.PLATE_ID).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.ROW).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.COLUMN).dataType(Column.ColumnDataType.INTEGER).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.ORGANISM).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.SPECIES).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.TISSUE).dataType(Column.ColumnDataType.STRING).build()); + columns.add(Column.builder().value(SampleSubmissionImport.Columns.COMMENTS).dataType(Column.ColumnDataType.STRING).build()); + + sortSamples(submission.get().getSamples()); List> rows = new ArrayList<>(); submission.get().getSamples().forEach(sample -> { Map row = new HashMap<>(); + row.put(SampleSubmissionImport.Columns.GERMPLASM_NAME, sample.getAdditionalInfo().get(BrAPIAdditionalInfoFields.GERMPLASM_NAME).getAsString()); + row.put(SampleSubmissionImport.Columns.GERMPLASM_GID, sample.getAdditionalInfo().get(BrAPIAdditionalInfoFields.GID).getAsString()); + row.put(SampleSubmissionImport.Columns.OBS_UNIT_ID, sample.getObservationUnitDbId()); + row.put(COLUMN_SAMPLE_NAME, sample.getSampleName()); row.put(SampleSubmissionImport.Columns.PLATE_ID, sample.getPlateName()); row.put(SampleSubmissionImport.Columns.ROW, sample.getRow()); row.put(SampleSubmissionImport.Columns.COLUMN, sample.getColumn()); row.put(SampleSubmissionImport.Columns.ORGANISM, sample.getAdditionalInfo().get(BrAPIAdditionalInfoFields.SAMPLE_ORGANISM).getAsString()); row.put(SampleSubmissionImport.Columns.SPECIES, sample.getAdditionalInfo().has(BrAPIAdditionalInfoFields.SAMPLE_SPECIES) ? sample.getAdditionalInfo().get(BrAPIAdditionalInfoFields.SAMPLE_SPECIES).getAsString() : ""); - row.put(COLUMN_GENOTYPE, sample.getSampleName()); row.put(SampleSubmissionImport.Columns.TISSUE, sample.getTissueType()); row.put(SampleSubmissionImport.Columns.COMMENTS, sample.getSampleDescription()); diff --git a/src/test/java/org/breedinginsight/api/v1/controller/SampleSubmissionControllerIntegrationTest.java b/src/test/java/org/breedinginsight/api/v1/controller/SampleSubmissionControllerIntegrationTest.java index 3c7cb0051..ddfadee9f 100644 --- a/src/test/java/org/breedinginsight/api/v1/controller/SampleSubmissionControllerIntegrationTest.java +++ b/src/test/java/org/breedinginsight/api/v1/controller/SampleSubmissionControllerIntegrationTest.java @@ -326,6 +326,48 @@ public void testGenerateDArTFile() throws IOException, InterruptedException, Par assertEquals("Genotype", lookupTable.column(5).name()); assertEquals(Columns.TISSUE, lookupTable.column(6).name()); assertEquals(Columns.COMMENTS, lookupTable.column(7).name()); + + //Check sorting + assertEquals("valid_1", lookupTable.column(0).get(1)); + assertEquals("A1", lookupTable.column(1).get(1)); + assertEquals(0, lookupTable.column(2).get(1)); + } + + @Test + public void testExportSampleSubmission() throws IOException, InterruptedException, ParsingException { + Pair>> uploadedSubmission = createSubmission(program); + + Flowable> call = client.exchange( + GET(String.format("/programs/%s/submissions/%s/export", + program.getId().toString(), uploadedSubmission.getLeft().getId())) + .cookie(new NettyCookie("phylo-token", "test-registered-user")), byte[].class + ); + HttpResponse response = call.blockingFirst(); + + assertEquals(HttpStatus.OK, response.getStatus()); + + ByteArrayInputStream bodyStream = new ByteArrayInputStream(Objects.requireNonNull(response.body())); + Table lookupTable = FileUtil.parseTableFromCsv(bodyStream); + assertEquals(11, lookupTable.columnCount()); + + //Check columns correct + assertEquals(Columns.GERMPLASM_NAME, lookupTable.column(0).name()); + assertEquals(Columns.GERMPLASM_GID, lookupTable.column(1).name()); + assertEquals(Columns.OBS_UNIT_ID, lookupTable.column(2).name()); + assertEquals("Sample Name", lookupTable.column(3).name()); + assertEquals(Columns.PLATE_ID, lookupTable.column(4).name()); + assertEquals(Columns.ROW, lookupTable.column(5).name()); + assertEquals(Columns.COLUMN, lookupTable.column(6).name()); + assertEquals(Columns.ORGANISM, lookupTable.column(7).name()); + assertEquals(Columns.SPECIES, lookupTable.column(8).name()); + assertEquals(Columns.TISSUE, lookupTable.column(9).name()); + assertEquals(Columns.COMMENTS, lookupTable.column(10).name()); + + //Check sorting + assertEquals(2, lookupTable.column(1).get(1)); + assertEquals("valid_1", lookupTable.column(4).get(1)); + assertEquals("A1", lookupTable.column(5).get(1)); + assertEquals(0, lookupTable.column(6).get(1)); } @Test