diff --git a/CHANGELOG.md b/CHANGELOG.md index 9063ead7058..603c2781305 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog +## [22.09.7] - Unreleased +* [UI]: Fixed bugs on NCBI Export page preventing the NCBI `submission.xml` file from being properly written. See [PR 1451](https://github.com/phac-nml/irida/pull/1451) + ## [22.09.6] - 2022/12/21 * [UI]: Fixed bug on NCBI Export page preventing the export from occuring. See [PR 1439](https://github.com/phac-nml/irida/pull/1439) diff --git a/build.gradle.kts b/build.gradle.kts index 2b612d2eea6..56726f2620f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,7 +14,7 @@ plugins { } group = "ca.corefacility.bioinformatics" -version = "22.09.6" +version = "22.09.7" description = "irida" java { diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UINcbiService.java b/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UINcbiService.java index dce3e7b7d1f..0998c4cba09 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UINcbiService.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UINcbiService.java @@ -14,14 +14,13 @@ import ca.corefacility.bioinformatics.irida.model.export.NcbiBioSampleFiles; import ca.corefacility.bioinformatics.irida.model.project.Project; import ca.corefacility.bioinformatics.irida.model.sequenceFile.SequenceFilePair; -import ca.corefacility.bioinformatics.irida.model.sequenceFile.SequencingObject; import ca.corefacility.bioinformatics.irida.model.sequenceFile.SingleEndSequenceFile; import ca.corefacility.bioinformatics.irida.model.user.User; import ca.corefacility.bioinformatics.irida.ria.web.ajax.dto.NcbiExportSubmissionTableModel; import ca.corefacility.bioinformatics.irida.ria.web.models.export.NcbiBioSampleModel; import ca.corefacility.bioinformatics.irida.ria.web.models.export.NcbiExportSubmissionAdminTableModel; -import ca.corefacility.bioinformatics.irida.ria.web.models.export.NcbiSubmissionRequest; import ca.corefacility.bioinformatics.irida.ria.web.models.export.NcbiSubmissionModel; +import ca.corefacility.bioinformatics.irida.ria.web.models.export.NcbiSubmissionRequest; import ca.corefacility.bioinformatics.irida.ria.web.models.tables.TableRequest; import ca.corefacility.bioinformatics.irida.ria.web.models.tables.TableResponse; import ca.corefacility.bioinformatics.irida.service.ProjectService; @@ -89,22 +88,8 @@ public TableResponse getNCBIExportsForAdmin */ public NcbiSubmissionModel getExportDetails(Long exportId) { NcbiExportSubmission submission = ncbiService.read(exportId); - Project project = projectService.read(submission.getProject() - .getId()); - List bioSamples = submission.getBioSampleFiles() - .stream() - .map(bioSampleFile -> { - List pairs = bioSampleFile.getPairs() - .stream() - .peek(pair -> uiSampleService.enhanceQcEntries(pair, project)) - .collect(Collectors.toList()); - List singles = bioSampleFile.getFiles() - .stream() - .peek(single -> uiSampleService.enhanceQcEntries(single, project)) - .collect(Collectors.toList()); - return new NcbiBioSampleModel(bioSampleFile); - }) + List bioSamples = submission.getBioSampleFiles().stream().map(NcbiBioSampleModel::new) .collect(Collectors.toList()); return new NcbiSubmissionModel(submission, bioSamples); diff --git a/src/main/resources/ca/corefacility/bioinformatics/irida/export/ncbi.xml b/src/main/resources/ca/corefacility/bioinformatics/irida/export/ncbi.xml index 5ce3ab345e0..30e7f3c18c8 100644 --- a/src/main/resources/ca/corefacility/bioinformatics/irida/export/ncbi.xml +++ b/src/main/resources/ca/corefacility/bioinformatics/irida/export/ncbi.xml @@ -1,7 +1,8 @@ @@ -17,13 +18,12 @@ - - IRIDA sequence files may either be plaintext (.fastq) or gzip compressed (.fastq.gz) - NCBI requires that uploaded files should have the appropriate file extension. - Determine if the IRIDA sequence file is compressed by looking for .gz extension - and add the appropriate extension to the uploaded files. - - + IRIDA sequence files may either be + plaintext (.fastq) or gzip compressed (.fastq.gz) NCBI requires that uploaded files should + have the appropriate file extension. Determine if the IRIDA sequence file is compressed by + looking for .gz extension and add the appropriate extension to the uploaded files. + generic-data @@ -34,13 +34,15 @@ generic-data - _Model_ + _Model_ _name_ _Strategy_ _Source_ - _Selection_ + + _Selection_ SINGLE - _Protocol_ + _Protocol_ _Project_ @@ -56,8 +58,10 @@ th:text="${sample.id}">_spuid_ - - + + generic-data @@ -67,7 +71,7 @@ generic-data - + generic-data @@ -77,13 +81,15 @@ generic-data - _Model_ + _Model_ _name_ _Strategy_ _Source_ - _Selection_ + + _Selection_ PAIRED - _Protocol_ + _Protocol_ _Project_ @@ -100,4 +106,4 @@ - + \ No newline at end of file diff --git a/src/main/webapp/resources/js/components/ncbi/details/utils.tsx b/src/main/webapp/resources/js/components/ncbi/details/utils.tsx index 95d23fc83f7..b9bf7ce6ce7 100644 --- a/src/main/webapp/resources/js/components/ncbi/details/utils.tsx +++ b/src/main/webapp/resources/js/components/ncbi/details/utils.tsx @@ -17,8 +17,14 @@ import ExportUploadStateTag from "../ExportUploadStateTag"; export const formatNcbiSubmissionDetails = ( submission: Omit ): BasicListItem[] => { + const LOCALE = window.TL?.LANGUAGE_TAG || "en"; const releaseDate = submission.releaseDate - ? formatInternationalizedDateTime(submission.releaseDate) + ? new Date(submission.releaseDate).toLocaleDateString(LOCALE, { + month: "short", + year: "numeric", + day: "numeric", + timeZone: "UTC", // ignoring timezone + }) : i18n("NcbiExportDetailsView.not-released"); return [ diff --git a/src/main/webapp/resources/js/pages/projects/ncbi/create/CreateNcbiExport.tsx b/src/main/webapp/resources/js/pages/projects/ncbi/create/CreateNcbiExport.tsx index cc2e04e1765..1175d092323 100644 --- a/src/main/webapp/resources/js/pages/projects/ncbi/create/CreateNcbiExport.tsx +++ b/src/main/webapp/resources/js/pages/projects/ncbi/create/CreateNcbiExport.tsx @@ -219,7 +219,7 @@ function CreateNcbiExport(): JSX.Element { pairs?: number[]; singles?: number[]; bioSample: string; - libraryName: { value: string }; + libraryName: string; libraryStrategy: { value: string }; librarySource: { value: string }; libraryConstructionProtocol: { value: string }; @@ -234,7 +234,7 @@ function CreateNcbiExport(): JSX.Element { bioProject, namespace, organization, - releaseDate: releaseDate.unix(), + releaseDate: releaseDate.endOf("day").valueOf(), samples: Object.values(_samples).map( ({ pairs = [], @@ -251,7 +251,7 @@ function CreateNcbiExport(): JSX.Element { singles, pairs, bioSample, - libraryName: libraryName.value, + libraryName, libraryStrategy: libraryStrategy.value, librarySource: librarySource.value, libraryConstructionProtocol: libraryConstructionProtocol.value, diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportPage.java b/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportPage.java index 0c52f7691a8..900f63208c1 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportPage.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportPage.java @@ -4,6 +4,7 @@ import java.util.List; import org.openqa.selenium.By; +import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; @@ -30,6 +31,9 @@ public class NcbiExportPage extends AbstractPage { @FindBy(xpath = "//*[@id=\"namespace\"]") private WebElement namespaceInput; + @FindBy(xpath = "//*[@id=\"releaseDate\"]") + private WebElement releaseDateInput; + @FindBy(className = "t-defaults-panel") private WebElement defaultsPanel; @@ -73,6 +77,12 @@ public void enterNamespace(String value) { namespaceInput.sendKeys(value); } + public void setReleaseDateInput(String value) { + releaseDateInput.sendKeys(Keys.chord(Keys.CONTROL, "a")); + releaseDateInput.sendKeys(value); + releaseDateInput.sendKeys(Keys.ENTER); + } + public void toggleDefaultsPanel() { defaultsPanel.click(); } diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportsListingPage.java b/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportsListingPage.java index fa8dafeb272..f3a53f1ca01 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportsListingPage.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/pages/projects/NcbiExportsListingPage.java @@ -1,11 +1,15 @@ package ca.corefacility.bioinformatics.irida.ria.integration.pages.projects; +import java.time.Duration; import java.util.List; +import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; import ca.corefacility.bioinformatics.irida.ria.integration.pages.AbstractPage; @@ -25,4 +29,11 @@ public static NcbiExportsListingPage goTo(WebDriver driver) { public int getNumberOfBioSampleIdsDisplayed() { return biodamplesIds.size(); } + + public void gotoSubmissionPage(String bioprojectId) { + WebElement link = driver.findElement(By.xpath("//table/tbody//a[text() = '" + bioprojectId + "']")); + link.click(); + WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); + wait.until(ExpectedConditions.urlMatches("/projects/\\d+/export/\\d+")); + } } diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/projects/NcbiExportPageIT.java b/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/projects/NcbiExportPageIT.java index d3408724ac4..4591e9dc5c5 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/projects/NcbiExportPageIT.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/ria/integration/projects/NcbiExportPageIT.java @@ -4,7 +4,9 @@ import ca.corefacility.bioinformatics.irida.ria.integration.AbstractIridaUIITChromeDriver; import ca.corefacility.bioinformatics.irida.ria.integration.pages.LoginPage; +import ca.corefacility.bioinformatics.irida.ria.integration.pages.projects.ExportDetailsPage; import ca.corefacility.bioinformatics.irida.ria.integration.pages.projects.NcbiExportPage; +import ca.corefacility.bioinformatics.irida.ria.integration.pages.projects.NcbiExportsListingPage; import ca.corefacility.bioinformatics.irida.ria.integration.pages.projects.ProjectSamplesPage; import com.github.springtestdbunit.annotation.DatabaseSetup; @@ -22,6 +24,7 @@ void testCreateNcbiSubmission() throws Exception { String SAMPLE_3 = "sample3"; String BIOPROJECT = "BIOPROJECT-1"; String NAMESPACE = "NAMESPACE-FOOBAR"; + String RELEASE_DATE = "2030-06-15"; String ORGANIZATION = "ORGANIZATION-FOOBAR"; String PROTOCOL = "AMAZING_PROTOCOL"; String DEFAULT_PROTOCOL = "DEFAULT_PROTOCOL"; @@ -40,6 +43,7 @@ void testCreateNcbiSubmission() throws Exception { page.enterBioProject(BIOPROJECT); page.enterNamespace(NAMESPACE); page.enterOrganization(ORGANIZATION); + page.setReleaseDateInput(RELEASE_DATE); // Test default sample settings. page.toggleDefaultsPanel(); @@ -84,5 +88,16 @@ void testCreateNcbiSubmission() throws Exception { assertTrue(page.isSuccessAlertDisplayed(), "Success notification should be displayed"); assertTrue(page.isUserRedirectedToProjectSamplesPage(PROJECT_ID), "User should be redirected within 5 seconds of submission"); + + // Make sure all fields submitted successfully + NcbiExportsListingPage listingPage = NcbiExportsListingPage.goTo(driver()); + listingPage.gotoSubmissionPage(BIOPROJECT); + + ExportDetailsPage detailsPage = ExportDetailsPage.initPage(driver()); + assertEquals(BIOPROJECT, detailsPage.getBioproject()); + assertEquals(NAMESPACE, detailsPage.getNamespace()); + + assertEquals(ORGANIZATION, detailsPage.getOrganization()); + assertTrue(detailsPage.getReleaseDate().equals("Jun 15, 2030")); } } diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/service/export/ExportUploadServiceTest.java b/src/test/java/ca/corefacility/bioinformatics/irida/service/export/ExportUploadServiceTest.java index fde45824baf..10c81c3892b 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/service/export/ExportUploadServiceTest.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/service/export/ExportUploadServiceTest.java @@ -1,44 +1,80 @@ package ca.corefacility.bioinformatics.irida.service.export; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; +import org.mockftpserver.fake.FakeFtpServer; +import org.mockftpserver.fake.UserAccount; +import org.mockftpserver.fake.filesystem.DirectoryEntry; +import org.mockftpserver.fake.filesystem.FileEntry; +import org.mockftpserver.fake.filesystem.FileSystem; +import org.mockftpserver.fake.filesystem.UnixFakeFileSystem; +import org.mockito.ArgumentCaptor; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; +import org.xmlunit.builder.DiffBuilder; +import org.xmlunit.diff.Diff; + import ca.corefacility.bioinformatics.irida.exceptions.UploadException; import ca.corefacility.bioinformatics.irida.model.NcbiExportSubmission; import ca.corefacility.bioinformatics.irida.model.enums.ExportUploadState; -import ca.corefacility.bioinformatics.irida.model.export.NcbiBioSampleFiles; +import ca.corefacility.bioinformatics.irida.model.export.*; import ca.corefacility.bioinformatics.irida.model.sample.MetadataTemplateField; import ca.corefacility.bioinformatics.irida.model.sample.Sample; import ca.corefacility.bioinformatics.irida.model.sample.SampleSequencingObjectJoin; import ca.corefacility.bioinformatics.irida.model.sample.metadata.MetadataEntry; import ca.corefacility.bioinformatics.irida.model.sequenceFile.SequenceFile; import ca.corefacility.bioinformatics.irida.model.sequenceFile.SingleEndSequenceFile; +import ca.corefacility.bioinformatics.irida.model.user.User; import ca.corefacility.bioinformatics.irida.service.impl.TestEmailController; import ca.corefacility.bioinformatics.irida.service.sample.MetadataTemplateService; import ca.corefacility.bioinformatics.irida.service.sample.SampleService; + import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; -import org.mockftpserver.fake.FakeFtpServer; -import org.mockftpserver.fake.UserAccount; -import org.mockftpserver.fake.filesystem.DirectoryEntry; -import org.mockftpserver.fake.filesystem.FileEntry; -import org.mockftpserver.fake.filesystem.FileSystem; -import org.mockftpserver.fake.filesystem.UnixFakeFileSystem; -import org.mockito.ArgumentCaptor; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; public class ExportUploadServiceTest { + private final Path TEST_NCBI_XML_PATH = Paths.get("src/test/resources/files/ncbi-export-test/example-ncbi.xml"); + + @Test + public void testCreateXml() throws IOException { + NcbiExportSubmission submission = createFakeSubmission(".fastq"); + + SpringTemplateEngine exportUploadTemplateEngine = new SpringTemplateEngine(); + + ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver(); + classLoaderTemplateResolver.setPrefix("/ca/corefacility/bioinformatics/irida/export/"); + classLoaderTemplateResolver.setSuffix(".xml"); + + classLoaderTemplateResolver.setTemplateMode(TemplateMode.XML); + classLoaderTemplateResolver.setCharacterEncoding("UTF-8"); + + exportUploadTemplateEngine.addTemplateResolver(classLoaderTemplateResolver); + + ExportUploadService exportUploadService = new ExportUploadService(null, null, null, exportUploadTemplateEngine, + new TestEmailController()); + + String xmlContent = assertDoesNotThrow(() -> exportUploadService.createXml(submission), + "createXml should not raise an exception with valid input."); + String expectedXmlContent = FileUtils.readFileToString(TEST_NCBI_XML_PATH.toFile(), "UTF-8"); + Diff xmlDiff = DiffBuilder.compare(expectedXmlContent) + .withTest(xmlContent) + .ignoreComments() + .ignoreWhitespace() + .withNodeFilter(node -> !(node.getNodeName().equals("Hold"))) + .build(); + assertFalse(xmlDiff.hasDifferences(), "the resulting xml is not correct"); + } @Test public void testUploadSubmission() throws UploadException, IOException { @@ -80,7 +116,12 @@ public void testUploadSubmission() throws UploadException, IOException { assertTrue(fileSystem.exists(createdDirectory + "/submission.xml"), "submission.xml created"); assertTrue(fileSystem.exists(createdDirectory + "/submit.ready"), "submit.ready created"); - SequenceFile createdFile = submission.getBioSampleFiles().iterator().next().getFiles().iterator().next() + SequenceFile createdFile = submission.getBioSampleFiles() + .iterator() + .next() + .getFiles() + .iterator() + .next() .getSequenceFile(); assertTrue(fileSystem.exists(createdDirectory + "/" + createdFile.getId() + ".fastq"), "seqfile created"); } @@ -125,7 +166,12 @@ public void testUploadSubmissionGzipped() throws UploadException, IOException { assertTrue(fileSystem.exists(createdDirectory + "/submission.xml"), "submission.xml created"); assertTrue(fileSystem.exists(createdDirectory + "/submit.ready"), "submit.ready created"); - SequenceFile createdFile = submission.getBioSampleFiles().iterator().next().getFiles().iterator().next() + SequenceFile createdFile = submission.getBioSampleFiles() + .iterator() + .next() + .getFiles() + .iterator() + .next() .getSequenceFile(); assertTrue(fileSystem.exists(createdDirectory + "/" + createdFile.getId() + ".fastq.gz"), "seqfile created"); } @@ -356,8 +402,7 @@ public void testGetResultsWithAccession() throws IOException, UploadException { Set savedMetadata = captor.getValue(); Optional metadataEntryOptional = savedMetadata.stream() - .filter(e -> e.getField() - .equals(field)) + .filter(e -> e.getField().equals(field)) .findAny(); assertTrue(metadataEntryOptional.isPresent(), "saved sample should contain accession"); } @@ -370,18 +415,22 @@ public void testGetResultsWithAccession() throws IOException, UploadException { * @throws IOException if the test file couldn't be created */ private NcbiExportSubmission createFakeSubmission(String sequenceFileExtension) throws IOException { - NcbiExportSubmission submission = new NcbiExportSubmission(); - submission.setId(1L); + User submitter = new User("username", "test@test.com", "password", "firstName", "lastName", "0000"); - NcbiBioSampleFiles ncbiBioSampleFiles = new NcbiBioSampleFiles(); Path tempFile = Files.createTempFile("sequencefile", sequenceFileExtension); SequenceFile sequenceFile = new SequenceFile(tempFile); sequenceFile.setId(1L); SingleEndSequenceFile singleFile = new SingleEndSequenceFile(sequenceFile); singleFile.setId(1L); - ncbiBioSampleFiles.setFiles(Sets.newHashSet(singleFile)); - submission.setBioSampleFiles(Lists.newArrayList(ncbiBioSampleFiles)); + NcbiBioSampleFiles ncbiBioSampleFiles = new NcbiBioSampleFiles("sample", Sets.newHashSet(singleFile), + Sets.newHashSet(), NcbiInstrumentModel.ILLUMINA_MI_SEQ, "library_name", NcbiLibrarySelection.CDNA, + NcbiLibrarySource.GENOMIC, NcbiLibraryStrategy.WGS, "library_construction_protocol", "namespace"); + ncbiBioSampleFiles.setId("a7f1d71e-8f86-4f0a-8f69-f79eca567f9d"); + + NcbiExportSubmission submission = new NcbiExportSubmission(null, submitter, "bioProjectId", "organization", + "ncbiNamespace", new Date(), Lists.newArrayList(ncbiBioSampleFiles)); + submission.setId(1L); return submission; diff --git a/src/test/resources/files/ncbi-export-test/example-ncbi.xml b/src/test/resources/files/ncbi-export-test/example-ncbi.xml new file mode 100644 index 00000000000..1738d3c1460 --- /dev/null +++ b/src/test/resources/files/ncbi-export-test/example-ncbi.xml @@ -0,0 +1,52 @@ + + + + + + organization + + + firstName + lastName + + + + + + + + + + + + + generic-data + + + Illumina MiSeq + library_name + WGS + GENOMIC + cDNA + SINGLE + library_construction_protocol + + + bioProjectId + + + + + sample + + + + a7f1d71e-8f86-4f0a-8f69-f79eca567f9d + + + + + \ No newline at end of file