diff --git a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/CommonOperationsClient.kt b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/CommonOperationsClient.kt index 2062f2b8f6..799f357a41 100644 --- a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/CommonOperationsClient.kt +++ b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/CommonOperationsClient.kt @@ -10,7 +10,7 @@ private const val GROUP_URL = "/groups" private const val PROJECTS_URL = "/projects" class CommonOperationsClient(private val template: RestTemplate) : GeneralOperations { - override fun getGroups(): List = template.getForObject>(GROUP_URL).orEmpty().toList() + override fun getGroups(): List = template.getForObject>(GROUP_URL).toList() - override fun getProjects(): List = template.getForObject>(PROJECTS_URL).orEmpty().toList() + override fun getProjects(): List = template.getForObject>(PROJECTS_URL).toList() } diff --git a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/ProjectClient.kt b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/ProjectClient.kt deleted file mode 100644 index dbd6cbd67f..0000000000 --- a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/ProjectClient.kt +++ /dev/null @@ -1,54 +0,0 @@ -package ac.uk.ebi.biostd.client.api - -import ac.uk.ebi.biostd.client.extensions.map -import ac.uk.ebi.biostd.client.integration.web.ProjectOperations -import ac.uk.ebi.biostd.integration.SerializationService -import ac.uk.ebi.biostd.integration.SubFormat -import ebi.ac.uk.model.Submission -import ebi.ac.uk.model.constants.FILES -import ebi.ac.uk.model.constants.PROJECT -import ebi.ac.uk.model.constants.SUBMISSION -import org.springframework.core.io.FileSystemResource -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.util.LinkedMultiValueMap -import org.springframework.web.client.RestTemplate -import org.springframework.web.client.postForEntity -import java.io.File - -class ProjectClient( - private val template: RestTemplate, - private val serializationService: SerializationService -) : ProjectOperations { - override fun submitProject(project: File): ResponseEntity { - val headers = HttpHeaders().apply { MediaType.MULTIPART_FORM_DATA } - val body = LinkedMultiValueMap().apply { - add(PROJECT, FileSystemResource(project)) - } - - return template - .postForEntity("/projects", HttpEntity(body, headers)) - .map { serializationService.deserializeSubmission(it, SubFormat.JSON_PRETTY) } - } - - override fun attachSubmission( - projectAccNo: String, - submission: File, - files: List - ): ResponseEntity { - val headers = HttpHeaders().apply { MediaType.MULTIPART_FORM_DATA } - val body = getMultipartBody(files, submission) - - return template - .postForEntity("/projects/$projectAccNo/submissions", HttpEntity(body, headers)) - .map { serializationService.deserializeSubmission(it, SubFormat.JSON_PRETTY) } - } - - private fun getMultipartBody(files: List, submission: File) = - LinkedMultiValueMap( - files.map { FILES to FileSystemResource(it) } - .plus(SUBMISSION to FileSystemResource(submission)) - .groupBy({ it.first }, { it.second })) -} diff --git a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionClientImpl.kt b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionClientImpl.kt index 6a59942909..879ffc5186 100644 --- a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionClientImpl.kt +++ b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionClientImpl.kt @@ -5,7 +5,6 @@ import ac.uk.ebi.biostd.client.integration.web.FilesOperations import ac.uk.ebi.biostd.client.integration.web.GeneralOperations import ac.uk.ebi.biostd.client.integration.web.GroupFilesOperations import ac.uk.ebi.biostd.client.integration.web.MultipartSubmissionOperations -import ac.uk.ebi.biostd.client.integration.web.ProjectOperations import ac.uk.ebi.biostd.client.integration.web.SubmissionClient import ac.uk.ebi.biostd.client.integration.web.SubmissionOperations import ac.uk.ebi.biostd.integration.SerializationService @@ -18,7 +17,6 @@ internal class SubmissionClientImpl( FilesOperations by UserFilesClient(template), GroupFilesOperations by GroupFilesClient(template), SubmissionOperations by SubmissionClient(template, serializationService), - ProjectOperations by ProjectClient(template, serializationService), MultipartSubmissionOperations by MultiPartSubmissionClient(template, serializationService), GeneralOperations by CommonOperationsClient(template), DraftSubmissionOperations by SubmissionDraftClient(template) diff --git a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmissionClient.kt b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmissionClient.kt index 6c7e2533cd..2f7ef85a00 100644 --- a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmissionClient.kt +++ b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmissionClient.kt @@ -21,7 +21,6 @@ interface SubmissionClient : SubmissionOperations, FilesOperations, GroupFilesOperations, - ProjectOperations, MultipartSubmissionOperations, GeneralOperations, DraftSubmissionOperations @@ -80,12 +79,6 @@ interface MultipartSubmissionOperations { ): ResponseEntity } -interface ProjectOperations { - fun submitProject(project: File): ResponseEntity - - fun attachSubmission(projectAccNo: String, submission: File, files: List): ResponseEntity -} - interface SecurityOperations { fun getAuthenticatedClient(user: String, password: String): BioWebClient diff --git a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/api/dto/SubmissionDto.kt b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/api/dto/SubmissionDto.kt index dd89433445..a7b5c197dc 100644 --- a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/api/dto/SubmissionDto.kt +++ b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/api/dto/SubmissionDto.kt @@ -1,5 +1,6 @@ package ebi.ac.uk.api.dto +import ebi.ac.uk.model.SubmissionMethod import java.time.OffsetDateTime data class SubmissionDto( @@ -8,5 +9,6 @@ data class SubmissionDto( val version: Int, val ctime: OffsetDateTime, val mtime: OffsetDateTime, - val rtime: OffsetDateTime? + val rtime: OffsetDateTime?, + val method: SubmissionMethod? ) diff --git a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/AccNumber.kt b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/AccNumber.kt index e51825df5a..1c867ef5ba 100644 --- a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/AccNumber.kt +++ b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/AccNumber.kt @@ -1,8 +1,10 @@ package ebi.ac.uk.model +import ebi.ac.uk.base.EMPTY + /** * Represents an submission accession number which include a pattern an a numeric value. */ -class AccNumber(val prefix: String, val numericValue: Long) { - override fun toString() = "$prefix$numericValue" +data class AccNumber(val prefix: String, val numericValue: Long? = null) { + override fun toString() = "$prefix${numericValue ?: EMPTY}" } diff --git a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/paths/SubmissionFolderResolver.kt b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/paths/SubmissionFolderResolver.kt index 70919bb6c9..d685178e44 100644 --- a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/paths/SubmissionFolderResolver.kt +++ b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/paths/SubmissionFolderResolver.kt @@ -10,6 +10,9 @@ class SubmissionFolderResolver(private val basePath: Path) { fun getSubmissionFolder(submission: ExtendedSubmission): Path = basePath.resolve(SUBMISSION_PATH).resolve(submission.relPath) + fun getSubmissionFolder(submissionRelPath: String): Path = + basePath.resolve(SUBMISSION_PATH).resolve(submissionRelPath) + fun getSubFilePath(relPath: String, fileName: String): Path = basePath.resolve(SUBMISSION_PATH).resolve(relPath).resolve(FILES_PATH).resolve(escapeFileName(fileName)) diff --git a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/persistence/PersistenceContext.kt b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/persistence/PersistenceContext.kt deleted file mode 100644 index 5b1fca7819..0000000000 --- a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/persistence/PersistenceContext.kt +++ /dev/null @@ -1,30 +0,0 @@ -package ebi.ac.uk.persistence - -import arrow.core.Option -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.Submission - -@Suppress("TooManyFunctions") -interface PersistenceContext { - fun createAccNoPatternSequence(pattern: String) - - fun getSequenceNextValue(pattern: String): Long - - fun getParentAccessTags(submission: Submission): List - - fun getParentAccPattern(submission: Submission): Option - - fun getSubmission(accNo: String): ExtendedSubmission? - - fun saveSubmission(submission: ExtendedSubmission): Submission - - fun isNew(accNo: String): Boolean - - fun saveAccessTag(accessTag: String) - - fun accessTagExists(accessTag: String): Boolean - - fun deleteSubmissionDrafts(submission: ExtendedSubmission) - - fun getSecret(accNo: String): String -} diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtAttribute.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtAttribute.kt index 6bf862ffe0..355c35e557 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtAttribute.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtAttribute.kt @@ -4,9 +4,13 @@ import ebi.ac.uk.extended.model.ExtAttribute import ebi.ac.uk.extended.model.ExtAttributeDetail import ebi.ac.uk.model.Attribute import ebi.ac.uk.model.AttributeDetail +import ebi.ac.uk.model.constants.SectionFields internal const val TO_EXT_ATTRIBUTE_EXTENSIONS = "ebi.ac.uk.extended.mapping.serialization.from.ToExtAttributeKt" -fun Attribute.toExtAttribute() = ExtAttribute(name, value, reference, toDetails(nameAttrs), toDetails(valueAttrs)) +fun Attribute.toExtAttribute(): ExtAttribute { + val attrValue = if (name == SectionFields.FILE_LIST.value) value.substringBeforeLast(".") else value + return ExtAttribute(name, attrValue, reference, toDetails(nameAttrs), toDetails(valueAttrs)) +} private fun toDetails(details: List) = details.map { ExtAttributeDetail(it.name, it.value) } diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtFileList.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtFileList.kt index 389a9d5ea4..dd17539e6d 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtFileList.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtFileList.kt @@ -7,4 +7,7 @@ import ebi.ac.uk.model.FileList internal const val TO_EXT_LIBRARY_FILE_EXTENSIONS = "ebi.ac.uk.extended.mapping.serialization.from.ToExtFileListKt" fun FileList.toExtFileList(fileSource: FilesSource): ExtFileList = - ExtFileList(name, fileSource.getFile(name), referencedFiles.map { it.toExtFile(fileSource) }) + ExtFileList( + name.substringBeforeLast("."), + fileSource.getFile(name), + referencedFiles.map { it.toExtFile(fileSource) }) diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSection.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSection.kt index 9386ad5863..125734f5d0 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSection.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSection.kt @@ -14,14 +14,5 @@ fun Section.toExtSection(source: FilesSource): ExtSection { attributes = attributes.map { it.toExtAttribute() }, files = files.map { either -> either.bimap({ it.toExtFile(source) }, { it.toExtTable(source) }) }, links = links.map { either -> either.bimap({ it.toExtLink() }, { it.toExtTable() }) }, - sections = sections.map { either -> either.bimap({ it.toExtSubSection(source) }, { it.toExtTable(source) }) }) -} - -fun Section.toExtSubSection(source: FilesSource): ExtSection { - return ExtSection( - type = type, - accNo = accNo, - fileList = fileList?.toExtFileList(source), - attributes = attributes.map { it.toExtAttribute() } - ) + sections = sections.map { either -> either.bimap({ it.toExtSection(source) }, { it.toExtTable(source) }) }) } diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSection.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSection.kt index 4fe4b36f27..297251b887 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSection.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSection.kt @@ -13,13 +13,5 @@ fun ExtSection.toSection(): Section { attributes = attributes.mapTo(mutableListOf()) { it.toAttribute() }, files = files.mapTo(mutableListOf()) { either -> either.bimap({ it.toFile() }, { it.toTable() }) }, links = links.mapTo(mutableListOf()) { either -> either.bimap({ it.toLink() }, { it.toTable() }) }, - sections = sections.mapTo(mutableListOf()) { either -> either.bimap({ it.toSubSection() }, { it.toTable() }) }) -} - -fun ExtSection.toSubSection(): Section { - return Section( - type = type, - accNo = accNo, - fileList = fileList?.toFileList(), - attributes = attributes.mapTo(mutableListOf()) { it.toAttribute() }) + sections = sections.mapTo(mutableListOf()) { either -> either.bimap({ it.toSection() }, { it.toTable() }) }) } diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSubmission.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSubmission.kt index 87eb611c7a..c8d062572c 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSubmission.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSubmission.kt @@ -1,7 +1,9 @@ package ebi.ac.uk.extended.mapping.serialization.to import ebi.ac.uk.extended.model.ExtSubmission +import ebi.ac.uk.model.Attribute import ebi.ac.uk.model.Submission +import ebi.ac.uk.model.constants.SubFields import ebi.ac.uk.model.extensions.creationTime import ebi.ac.uk.model.extensions.modificationTime import ebi.ac.uk.model.extensions.releaseTime @@ -14,11 +16,20 @@ fun ExtSubmission.toSimpleSubmission(): Submission { return Submission( accNo = accNo, section = section.toSection(), - attributes = attributes.map { it.toAttribute() }.toMutableList(), + attributes = getSubmissionAttributes(), tags = tags.mapTo(mutableListOf()) { Pair(it.name, it.value) } ) } +private fun ExtSubmission.getSubmissionAttributes(): List { + val subAttrs = attributes.map { it.toAttribute() }.toMutableList() + + return when (releaseTime) { + null -> subAttrs + else -> subAttrs.plus(Attribute(SubFields.RELEASE_DATE, releaseTime.toLocalDate())) + } +} + /** * Return a extended submission which contains submission secret information and internal information. */ diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtSubmissionExtensions.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtSubmissionExtensions.kt index 18cb999aa8..9b7c757229 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtSubmissionExtensions.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtSubmissionExtensions.kt @@ -9,5 +9,5 @@ val ExtSubmission.allReferencedFiles val ExtSubmission.allFiles get(): List = allSections.flatMap { it.allFiles } -val ExtSubmission.allFileLists +val ExtSubmission.allFileListSections get(): List = allSections.mapNotNull { it.fileList } diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtendedModel.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtendedModel.kt index 0055f9ca8f..a1d4c275c2 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtendedModel.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/model/ExtendedModel.kt @@ -1,6 +1,7 @@ package ebi.ac.uk.extended.model import arrow.core.Either +import ebi.ac.uk.model.SubmissionMethod import ebi.ac.uk.model.constants.ProcessingStatus import java.io.File import java.time.OffsetDateTime @@ -38,7 +39,9 @@ data class ExtSection( data class ExtSubmission( val accNo: String, + var version: Int, val title: String?, + val method: SubmissionMethod, val relPath: String, val rootPath: String?, val released: Boolean, diff --git a/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSectionTest.kt b/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSectionTest.kt index 7838f85a93..14b9599b74 100644 --- a/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSectionTest.kt +++ b/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/from/ToExtSectionTest.kt @@ -8,7 +8,6 @@ import ebi.ac.uk.extended.model.ExtFileList import ebi.ac.uk.extended.model.ExtFileTable import ebi.ac.uk.extended.model.ExtLink import ebi.ac.uk.extended.model.ExtLinkTable -import ebi.ac.uk.extended.model.ExtSection import ebi.ac.uk.extended.model.ExtSectionTable import ebi.ac.uk.io.sources.FilesSource import ebi.ac.uk.model.Attribute @@ -37,7 +36,6 @@ class ToExtSectionTest( @MockK val fileTable: FilesTable, @MockK val link: Link, @MockK val linkTable: LinksTable, - @MockK val subsection: Section, @MockK val sectionTable: SectionsTable, @MockK val extFileList: ExtFileList, @MockK val extAttribute: ExtAttribute, @@ -45,9 +43,9 @@ class ToExtSectionTest( @MockK val extFileTable: ExtFileTable, @MockK val extLink: ExtLink, @MockK val extLinkTable: ExtLinkTable, - @MockK val extSubsection: ExtSection, @MockK val extSectionTable: ExtSectionTable ) { + private val subSection = Section(type = "subtype", accNo = "accNo1") private val section = Section( type = "type", accNo = "accNo", @@ -55,7 +53,7 @@ class ToExtSectionTest( attributes = listOf(attribute), files = mutableListOf(left(file), right(fileTable)), links = mutableListOf(left(link), right(linkTable)), - sections = mutableListOf(left(subsection), right(sectionTable)) + sections = mutableListOf(left(subSection), right(sectionTable)) ) @Test @@ -76,7 +74,6 @@ class ToExtSectionTest( every { linkTable.toExtTable() } returns extLinkTable every { sectionTable.toExtTable(fileSource) } returns extSectionTable every { fileList.toExtFileList(fileSource) } returns extFileList - every { subsection.toExtSubSection(fileSource) } returns extSubsection val sectionResult = section.toExtSection(fileSource) assertThat(sectionResult.accNo).isEqualTo(section.accNo) @@ -87,8 +84,11 @@ class ToExtSectionTest( assertThat(sectionResult.files.second()).isEqualTo(right(extFileTable)) assertThat(sectionResult.links.first()).isEqualTo(left(extLink)) assertThat(sectionResult.links.second()).isEqualTo(right(extLinkTable)) - assertThat(sectionResult.sections.first()).isEqualTo(left(extSubsection)) assertThat(sectionResult.sections.second()).isEqualTo(right(extSectionTable)) + sectionResult.sections.first().mapLeft { + assertThat(it.type).isEqualTo("subtype") + assertThat(it.accNo).isEqualTo("accNo1") + } } } } diff --git a/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSectionTest.kt b/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSectionTest.kt index b9adca4c22..92a07bc3f1 100644 --- a/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSectionTest.kt +++ b/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/mapping/serialization/to/ToSectionTest.kt @@ -16,7 +16,6 @@ import ebi.ac.uk.model.FileList import ebi.ac.uk.model.FilesTable import ebi.ac.uk.model.Link import ebi.ac.uk.model.LinksTable -import ebi.ac.uk.model.Section import ebi.ac.uk.model.SectionsTable import ebi.ac.uk.util.collections.second import io.mockk.every @@ -35,7 +34,6 @@ class ToSectionTest( @MockK val fileTable: FilesTable, @MockK val link: Link, @MockK val linkTable: LinksTable, - @MockK val subsection: Section, @MockK val sectionTable: SectionsTable, @MockK val extFileList: ExtFileList, @MockK val extAttribute: ExtAttribute, @@ -43,9 +41,9 @@ class ToSectionTest( @MockK val extFileTable: ExtFileTable, @MockK val extLink: ExtLink, @MockK val extLinkTable: ExtLinkTable, - @MockK val extSubsection: ExtSection, @MockK val extSectionTable: ExtSectionTable ) { + private val subSection = ExtSection(type = "subtype", accNo = "accNo1") private val section = ExtSection( type = "type", accNo = "accNo", @@ -53,7 +51,7 @@ class ToSectionTest( attributes = listOf(extAttribute), files = listOf(left(extFile), right(extFileTable)), links = listOf(left(extLink), right(extLinkTable)), - sections = listOf(left(extSubsection), right(extSectionTable)) + sections = listOf(left(subSection), right(extSectionTable)) ) @Test @@ -74,7 +72,6 @@ class ToSectionTest( every { extLinkTable.toTable() } returns linkTable every { extSectionTable.toTable() } returns sectionTable every { extFileList.toFileList() } returns fileList - every { extSubsection.toSubSection() } returns subsection val sectionResult = section.toSection() assertThat(sectionResult.accNo).isEqualTo(section.accNo) @@ -85,8 +82,11 @@ class ToSectionTest( assertThat(sectionResult.files.second()).isEqualTo(right(fileTable)) assertThat(sectionResult.links.first()).isEqualTo(left(link)) assertThat(sectionResult.links.second()).isEqualTo(right(linkTable)) - assertThat(sectionResult.sections.first()).isEqualTo(left(subsection)) assertThat(sectionResult.sections.second()).isEqualTo(right(sectionTable)) + sectionResult.sections.first().mapLeft { + assertThat(it.type).isEqualTo("subtype") + assertThat(it.accNo).isEqualTo("accNo1") + } } } } diff --git a/submission/persistence/build.gradle b/submission/persistence/build.gradle index 79a9ce476e..260adddcf1 100644 --- a/submission/persistence/build.gradle +++ b/submission/persistence/build.gradle @@ -10,6 +10,7 @@ plugins { dependencies { compile project(":commons:commons-util") compile project(":commons:commons-bio") + compile project(":commons:commons-serialization") compile project(":commons:commons-model-extended") compile(project(":commons:commons-test")) diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilter.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilter.kt index 2511817b53..1818f1fc37 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilter.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilter.kt @@ -3,6 +3,7 @@ package ac.uk.ebi.biostd.persistence.filter class SubmissionFilter( val accNo: String? = null, val version: Long? = null, + val type: String? = null, val rTimeFrom: String? = null, val rTimeTo: String? = null, val keywords: String? = null, diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilterSpecification.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilterSpecification.kt index fdc38d3e36..36db9d0c6b 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilterSpecification.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/filter/SubmissionFilterSpecification.kt @@ -1,5 +1,6 @@ package ac.uk.ebi.biostd.persistence.filter +import ac.uk.ebi.biostd.persistence.model.Section import ac.uk.ebi.biostd.persistence.model.Submission import ac.uk.ebi.biostd.persistence.model.User import ebi.ac.uk.base.applyIfNotBlank @@ -15,6 +16,7 @@ class SubmissionFilterSpecification(userId: Long, filter: SubmissionFilter) { filter.keywords?.applyIfNotBlank { specs = specs and (withTitleLike(it)) } filter.rTimeTo?.let { specs = specs and (withTo(OffsetDateTime.parse(it))) } filter.rTimeFrom?.let { specs = specs and (withFrom(OffsetDateTime.parse(it))) } + filter.type?.let { specs = specs and (withType(it)) } specification = specs } @@ -25,6 +27,9 @@ class SubmissionFilterSpecification(userId: Long, filter: SubmissionFilter) { private fun withAccession(accNo: String): Specification = Specification { root, _, cb -> cb.equal(root.get("accNo"), accNo) } + private fun withType(type: String): Specification = + Specification { root, _, cb -> cb.equal(root.get
("rootSection").get("type"), type) } + private fun withTitleLike(title: String): Specification = Specification { root, _, cb -> cb.like(cb.lower(root.get("title")), "%" + title.toLowerCase() + "%") } diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/integration/PersistenceContext.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/integration/PersistenceContext.kt new file mode 100644 index 0000000000..8039052b7c --- /dev/null +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/integration/PersistenceContext.kt @@ -0,0 +1,38 @@ +package ac.uk.ebi.biostd.persistence.integration + +import arrow.core.Option +import ebi.ac.uk.extended.model.ExtSubmission +import java.time.OffsetDateTime + +@Suppress("TooManyFunctions") +interface PersistenceContext { + fun createAccNoPatternSequence(pattern: String) + + fun getSequenceNextValue(pattern: String): Long + + fun getParentAccPattern(parentAccNo: String): Option + + fun isNew(accNo: String): Boolean + + fun saveAccessTag(accessTag: String) + + fun accessTagExists(accessTag: String): Boolean + + fun deleteSubmissionDrafts(userId: Long, accNo: String) + + fun getSecret(accNo: String): String + + fun getAccessTags(accNo: String): List + + fun getReleaseTime(accNo: String): OffsetDateTime? + + fun existByAccNo(accNo: String): Boolean + + fun getNextVersion(accNo: String): Int + + fun findCreationTime(accNo: String): OffsetDateTime? + + fun saveSubmission(submission: ExtSubmission, submitter: String, submitterId: Long): ExtSubmission + + fun getAuthor(accNo: String): String +} diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/integration/PersistenceContextImpl.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/integration/PersistenceContextImpl.kt index 70e251773a..920b31bbb3 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/integration/PersistenceContextImpl.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/integration/PersistenceContextImpl.kt @@ -1,35 +1,34 @@ package ac.uk.ebi.biostd.persistence.integration import ac.uk.ebi.biostd.persistence.exception.ProjectNotFoundException -import ac.uk.ebi.biostd.persistence.mapping.SubmissionDbMapper -import ac.uk.ebi.biostd.persistence.mapping.SubmissionMapper +import ac.uk.ebi.biostd.persistence.mapping.extended.from.ToDbSubmissionMapper +import ac.uk.ebi.biostd.persistence.mapping.extended.to.ToExtSubmissionMapper import ac.uk.ebi.biostd.persistence.model.AccessTag import ac.uk.ebi.biostd.persistence.model.Sequence -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.LockExecutor import ac.uk.ebi.biostd.persistence.repositories.SequenceDataRepository import ac.uk.ebi.biostd.persistence.repositories.SubmissionDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataDataRepository -import arrow.core.getOrElse +import ac.uk.ebi.biostd.persistence.service.FilePersistenceService import arrow.core.toOption -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.Submission +import ebi.ac.uk.extended.model.ExtSubmission import ebi.ac.uk.model.constants.SubFields.ACC_NO_TEMPLATE -import ebi.ac.uk.model.extensions.attachTo -import ebi.ac.uk.persistence.PersistenceContext import ebi.ac.uk.util.collections.ifNotEmpty import org.springframework.transaction.annotation.Isolation import org.springframework.transaction.annotation.Transactional +import java.time.OffsetDateTime @Suppress("TooManyFunctions") open class PersistenceContextImpl( private val subRepository: SubmissionDataRepository, private val sequenceRepository: SequenceDataRepository, - private val accessTagsDataRepository: AccessTagDataRepository, + private val accessTagsDataRepository: AccessTagDataRepo, private val lockExecutor: LockExecutor, - private val subDbMapper: SubmissionDbMapper, - private val subMapper: SubmissionMapper, - private val userDataRepository: UserDataDataRepository + private val userDataRepository: UserDataDataRepository, + private val toDbSubmissionMapper: ToDbSubmissionMapper, + private val toExtSubmissionMapper: ToExtSubmissionMapper, + private val filePersistenceService: FilePersistenceService ) : PersistenceContext { override fun createAccNoPatternSequence(pattern: String) { sequenceRepository.save(Sequence(pattern)) @@ -37,44 +36,63 @@ open class PersistenceContextImpl( @Transactional override fun getSequenceNextValue(pattern: String): Long { - val sequence = sequenceRepository.getByPrefix(pattern) - sequence.counter.count = sequence.counter.count + 1 - sequenceRepository.save(sequence) - return sequence.counter.count + return lockExecutor.executeLocking(pattern) { + val sequence = sequenceRepository.getByPrefix(pattern) + sequence.counter.count = sequence.counter.count + 1 + sequenceRepository.save(sequence).counter.count + } } - override fun getParentAccessTags(submission: Submission): List = - getParentSubmission(submission) - .map { it.accessTags } - .getOrElse { emptyList() } - .map { it.name } - - override fun getParentAccPattern(submission: Submission) = - getParentSubmission(submission) + override fun getParentAccPattern(parentAccNo: String) = + getParentSubmission(parentAccNo) + .toOption() .flatMap { parent -> parent.attributes.firstOrNull { it.name == ACC_NO_TEMPLATE.value }.toOption() } .map { it.value } - override fun getSubmission(accNo: String) = - subRepository.findByAccNoAndVersionGreaterThan(accNo)?.let { subDbMapper.toExtSubmission(it) } + private fun getSubmission(accNo: String) = subRepository.findByAccNoAndVersionGreaterThan(accNo) @Transactional(isolation = Isolation.READ_UNCOMMITTED) - override fun saveSubmission(submission: ExtendedSubmission): Submission { + override fun saveSubmission(submission: ExtSubmission, submitter: String, submitterId: Long): ExtSubmission { return lockExecutor.executeLocking(submission.accNo) { - val nextVersion = (subRepository.getLastVersion(submission.accNo) ?: 0) + 1 subRepository.expireActiveVersions(submission.accNo) - submission.version = nextVersion - subDbMapper.toSubmission(subRepository.save(subMapper.toSubmissionDb(submission))) + val dbSubmission = toDbSubmissionMapper.toSubmissionDb(submission, submitter) + val persistedSubmission = toExtSubmissionMapper.toExtSubmission(subRepository.save(dbSubmission)) + filePersistenceService.persistSubmissionFiles(submission) + deleteSubmissionDrafts(submitterId, submission.accNo) + persistedSubmission } } - override fun deleteSubmissionDrafts(submission: ExtendedSubmission) { - userDataRepository.findByUserIdAndKeyIgnoreCaseContaining(submission.user.id, submission.accNo).ifNotEmpty { + override fun getAuthor(accNo: String): String { + return getSubmission(accNo)!!.owner.email + } + + override fun deleteSubmissionDrafts(userId: Long, accNo: String) { + userDataRepository.findByUserIdAndKeyIgnoreCaseContaining(userId, accNo).ifNotEmpty { userDataRepository.deleteAll(it) } } override fun getSecret(accNo: String): String = getSubmission(accNo)!!.secretKey + override fun getAccessTags(accNo: String): List { + return subRepository.getByAccNoAndVersionGreaterThan(accNo, 0).accessTags.map { it.name } + } + + override fun getReleaseTime(accNo: String): OffsetDateTime? { + return subRepository.getByAccNoAndVersionGreaterThan(accNo, 0).releaseTime + } + + override fun findCreationTime(accNo: String): OffsetDateTime? { + return subRepository.findByAccNoAndVersionGreaterThan(accNo, 0)?.creationTime + } + + override fun existByAccNo(accNo: String): Boolean { + return subRepository.existsByAccNo(accNo) + } + + override fun getNextVersion(accNo: String): Int = (subRepository.getLastVersion(accNo) ?: 0) + 1 + override fun saveAccessTag(accessTag: String) { accessTagsDataRepository.save(AccessTag(name = accessTag)) } @@ -83,8 +101,6 @@ open class PersistenceContextImpl( override fun isNew(accNo: String) = subRepository.existsByAccNo(accNo).not() - private fun getParentSubmission(submission: Submission) = - submission.attachTo?.let { - subRepository.findByAccNoAndVersionGreaterThan(it) ?: throw ProjectNotFoundException(it) - }.toOption() + private fun getParentSubmission(parentAccNo: String) = + subRepository.findByAccNoAndVersionGreaterThan(parentAccNo) ?: throw ProjectNotFoundException(parentAccNo) } diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/SubmissionMapper.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/SubmissionMapper.kt index ef65285f3f..e29f5fb90e 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/SubmissionMapper.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/SubmissionMapper.kt @@ -15,7 +15,7 @@ import ac.uk.ebi.biostd.persistence.model.LinkAttribute import ac.uk.ebi.biostd.persistence.model.ReferencedFileAttribute import ac.uk.ebi.biostd.persistence.model.SectionAttribute import ac.uk.ebi.biostd.persistence.model.SubmissionAttribute -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.TagDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository import arrow.core.Either @@ -44,7 +44,7 @@ import ac.uk.ebi.biostd.persistence.model.Section as SectionDb import ac.uk.ebi.biostd.persistence.model.Submission as SubmissionDb class SubmissionMapper( - private val tagsRepository: AccessTagDataRepository, + private val tagsRepository: AccessTagDataRepo, private val tagsRefRepository: TagDataRepository, private var userRepository: UserDataRepository ) { diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapper.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapper.kt index b4d54dfb93..e9ec2aa307 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapper.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapper.kt @@ -1,7 +1,7 @@ package ac.uk.ebi.biostd.persistence.mapping.extended.from import ac.uk.ebi.biostd.persistence.model.SubmissionAttribute -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.TagDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository import ebi.ac.uk.extended.model.ExtAccessTag @@ -13,7 +13,7 @@ import ac.uk.ebi.biostd.persistence.model.Submission as SubmissionDb private const val ROOT_SECTION_ORDER = 0 class ToDbSubmissionMapper( - private val tagsRepository: AccessTagDataRepository, + private val tagsRepository: AccessTagDataRepo, private val tagsRefRepository: TagDataRepository, private var userRepository: UserDataRepository ) { @@ -21,6 +21,8 @@ class ToDbSubmissionMapper( accNo = submission.accNo title = submission.title status = submission.status + method = submission.method + version = submission.version relPath = submission.relPath rootPath = submission.rootPath secretKey = submission.secretKey diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/to/ToExtSubmissionMapper.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/to/ToExtSubmissionMapper.kt index 028d225084..688bad3857 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/to/ToExtSubmissionMapper.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/to/ToExtSubmissionMapper.kt @@ -17,6 +17,8 @@ class ToExtSubmissionMapper(private val submissionsPath: Path) { return ExtSubmission( accNo = dbSubmission.accNo, title = dbSubmission.title, + version = dbSubmission.version, + method = dbSubmission.method!!, // FIX this add default status status = dbSubmission.status, relPath = dbSubmission.relPath, rootPath = dbSubmission.rootPath, diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/projections/SimpleSubmission.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/projections/SimpleSubmission.kt index e3ff32af36..965da100ae 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/projections/SimpleSubmission.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/projections/SimpleSubmission.kt @@ -2,6 +2,7 @@ package ac.uk.ebi.biostd.persistence.projections import ac.uk.ebi.biostd.persistence.model.SIMPLE_QUERY_GRAPH import ebi.ac.uk.functions.secondsToInstant +import ebi.ac.uk.model.SubmissionMethod import ebi.ac.uk.model.constants.ProcessingStatus import java.time.OffsetDateTime import java.time.ZoneOffset @@ -20,6 +21,7 @@ data class SimpleSubmission( val releaseTime: OffsetDateTime?, val modificationTime: OffsetDateTime, val creationTime: OffsetDateTime, + val method: SubmissionMethod?, var status: ProcessingStatus ) { @@ -37,7 +39,8 @@ data class SimpleSubmission( creationTime = creationTime, modificationTime = modificationTime, releaseTime = releaseTime, - status = status + status = status, + method = method ) } diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/repositories/Repositories.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/repositories/Repositories.kt index c1a5c6a007..2bc3fdafec 100644 --- a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/repositories/Repositories.kt +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/repositories/Repositories.kt @@ -52,7 +52,7 @@ interface SubmissionDataRepository : ): List } -interface AccessTagDataRepository : JpaRepository { +interface AccessTagDataRepo : JpaRepository { fun findByName(name: String): AccessTag fun existsByName(name: String): Boolean } @@ -84,8 +84,9 @@ interface UserGroupDataRepository : JpaRepository { } interface AccessPermissionRepository : JpaRepository { - fun existsByAccessTagNameInAndAccessType(accessTags: List, accessType: AccessType): Boolean fun findByUserIdAndAccessType(userId: Long, accessType: AccessType): List + fun existsByAccessTagNameInAndAccessType(accessTags: List, accessType: AccessType): Boolean + fun existsByUserEmailAndAccessTypeAndAccessTagName(user: String, type: AccessType, accessTag: String): Boolean } interface UserDataDataRepository : JpaRepository { diff --git a/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/service/FilePersistenceService.kt b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/service/FilePersistenceService.kt new file mode 100644 index 0000000000..6921c7343b --- /dev/null +++ b/submission/persistence/src/main/kotlin/ac/uk/ebi/biostd/persistence/service/FilePersistenceService.kt @@ -0,0 +1,50 @@ +package ac.uk.ebi.biostd.persistence.service + +import ac.uk.ebi.biostd.integration.SerializationService +import ac.uk.ebi.biostd.integration.SubFormat +import ebi.ac.uk.extended.mapping.serialization.to.toSimpleSubmission +import ebi.ac.uk.extended.model.ExtFile +import ebi.ac.uk.extended.model.ExtSubmission +import ebi.ac.uk.extended.model.allFileListSections +import ebi.ac.uk.extended.model.allFiles +import ebi.ac.uk.extended.model.allReferencedFiles +import ebi.ac.uk.paths.SubmissionFolderResolver +import org.apache.commons.io.FileUtils + +class FilePersistenceService( + private val folderResolver: SubmissionFolderResolver, + private val serializationService: SerializationService +) { + fun persistSubmissionFiles(submission: ExtSubmission) { + persistFiles(submission) + generateOutputFiles(submission) + } + + private fun persistFiles(submission: ExtSubmission) { + copy(submission.allFiles, submission.relPath) + copy(submission.allReferencedFiles, submission.relPath) + } + + private fun generateOutputFiles(submission: ExtSubmission) { + generateOutputFiles(submission.toSimpleSubmission(), submission, submission.accNo) + submission.allFileListSections.forEach { generateOutputFiles(it, submission, it.fileName) } + } + + private fun copy(files: List, submissionRelPath: String) { + files.forEach { extFile -> + val submissionFile = folderResolver.getSubFilePath(submissionRelPath, extFile.fileName).toFile() + FileUtils.copyFile(extFile.file, submissionFile) + } + } + + private fun generateOutputFiles(element: T, submission: ExtSubmission, outputFileName: String) { + val json = serializationService.serializeElement(element, SubFormat.JSON_PRETTY) + val xml = serializationService.serializeElement(element, SubFormat.XML) + val tsv = serializationService.serializeElement(element, SubFormat.TSV) + val submissionPath = folderResolver.getSubmissionFolder(submission.relPath) + + FileUtils.writeStringToFile(submissionPath.resolve("$outputFileName.json").toFile(), json, Charsets.UTF_8) + FileUtils.writeStringToFile(submissionPath.resolve("$outputFileName.xml").toFile(), xml, Charsets.UTF_8) + FileUtils.writeStringToFile(submissionPath.resolve("$outputFileName.pagetab.tsv").toFile(), tsv, Charsets.UTF_8) + } +} diff --git a/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapperTest.kt b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapperTest.kt index 3a989a44ab..92b349e130 100644 --- a/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapperTest.kt +++ b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/mapping/extended/from/ToDbSubmissionMapperTest.kt @@ -3,7 +3,7 @@ package ac.uk.ebi.biostd.persistence.mapping.extended.from import ac.uk.ebi.biostd.persistence.model.AccessTag import ac.uk.ebi.biostd.persistence.model.Tag import ac.uk.ebi.biostd.persistence.model.User -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.TagDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository import ac.uk.ebi.biostd.persistence.test.assertSubmission @@ -20,7 +20,7 @@ private const val submitter = "user@ebi.email.com" @ExtendWith(MockKExtension::class) internal class ToDbSubmissionMapperTest( - @MockK private val accessTagsRepository: AccessTagDataRepository, + @MockK private val accessTagsRepository: AccessTagDataRepo, @MockK private val tagsRepository: TagDataRepository, @MockK private var userRepository: UserDataRepository ) { diff --git a/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/service/FilePersistenceServiceTest.kt b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/service/FilePersistenceServiceTest.kt new file mode 100644 index 0000000000..c20a42e9b4 --- /dev/null +++ b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/service/FilePersistenceServiceTest.kt @@ -0,0 +1,70 @@ +package ac.uk.ebi.biostd.persistence.service + +import ac.uk.ebi.biostd.integration.SerializationService +import ac.uk.ebi.biostd.integration.SubFormat.Companion.JSON_PRETTY +import ac.uk.ebi.biostd.integration.SubFormat.Companion.TSV +import ac.uk.ebi.biostd.integration.SubFormat.Companion.XML +import ac.uk.ebi.biostd.persistence.test.extSubmissionWithFileList +import ebi.ac.uk.extended.mapping.serialization.to.toSimpleSubmission +import ebi.ac.uk.extended.model.allFileListSections +import ebi.ac.uk.paths.SubmissionFolderResolver +import io.github.glytching.junit.extension.folder.TemporaryFolder +import io.github.glytching.junit.extension.folder.TemporaryFolderExtension +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.junit5.MockKExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import java.nio.file.Paths + +@ExtendWith(TemporaryFolderExtension::class, MockKExtension::class) +class FilePersistenceServiceTest( + private val temporaryFolder: TemporaryFolder, + @MockK private val mockFolderResolver: SubmissionFolderResolver, + @MockK private val mockSerializationService: SerializationService +) { + private val sectionFile = createTempFile("file.txt") + private val fileList = createTempFile("fileList.json") + private val referencedFile = createTempFile("file2.txt") + private val extSubmission = extSubmissionWithFileList(listOf(sectionFile), fileList, listOf(referencedFile)) + private val relPath = extSubmission.relPath + + private val testInstance = FilePersistenceService(mockFolderResolver, mockSerializationService) + + @BeforeEach + fun beforeEach() { + every { mockFolderResolver.getSubmissionFolder(relPath) } returns getPath(relPath) + every { mockFolderResolver.getSubFilePath(relPath, sectionFile.name) } returns getPath("$relPath/file.txt") + every { mockFolderResolver.getSubFilePath(relPath, referencedFile.name) } returns getPath("$relPath/file2.txt") + + val simpleSubmission = extSubmission.toSimpleSubmission() + every { mockSerializationService.serializeElement(simpleSubmission, XML) } returns "" + every { mockSerializationService.serializeElement(simpleSubmission, TSV) } returns "" + every { mockSerializationService.serializeElement(simpleSubmission, JSON_PRETTY) } returns "" + + val sectionFileList = extSubmission.allFileListSections.first() + every { mockSerializationService.serializeElement(sectionFileList, XML) } returns "" + every { mockSerializationService.serializeElement(sectionFileList, TSV) } returns "" + every { mockSerializationService.serializeElement(sectionFileList, JSON_PRETTY) } returns "" + } + + @Test + fun persistSubmissionFiles() { + testInstance.persistSubmissionFiles(extSubmission) + + assertThat(getPath("$relPath/file.txt")).exists() + assertThat(getPath("$relPath/file2.txt")).exists() + + assertThat(getPath("$relPath/ABC-123.xml")).exists() + assertThat(getPath("$relPath/ABC-123.json")).exists() + assertThat(getPath("$relPath/ABC-123.pagetab.tsv")).exists() + + assertThat(getPath("$relPath/fileList.xml")).exists() + assertThat(getPath("$relPath/fileList.json")).exists() + assertThat(getPath("$relPath/fileList.pagetab.tsv")).exists() + } + + private fun getPath(path: String) = Paths.get("${temporaryFolder.root.absolutePath}/$path") +} diff --git a/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/test/ExtSubmissionFactory.kt b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/test/ExtSubmissionFactory.kt new file mode 100644 index 0000000000..d13678b002 --- /dev/null +++ b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/test/ExtSubmissionFactory.kt @@ -0,0 +1,37 @@ +package ac.uk.ebi.biostd.persistence.test + +import arrow.core.Either.Companion.left +import ebi.ac.uk.extended.model.ExtFile +import ebi.ac.uk.extended.model.ExtFileList +import ebi.ac.uk.extended.model.ExtSection +import ebi.ac.uk.extended.model.ExtSubmission +import ebi.ac.uk.model.SubmissionMethod +import ebi.ac.uk.model.constants.ProcessingStatus +import java.io.File +import java.time.OffsetDateTime +import java.time.ZoneOffset + +fun extSubmissionWithFileList(files: List, fileList: File, referencedFiles: List) = + ExtSubmission( + accNo = "ABC-123", + version = 1, + title = "A Test Submission", + method = SubmissionMethod.PAGE_TAB, + relPath = "/ABC/ABCxxx123/ABC-123", + rootPath = null, + released = false, + secretKey = "a-secret-key", + status = ProcessingStatus.PROCESSED, + releaseTime = null, + modificationTime = OffsetDateTime.of(2018, 10, 10, 0, 0, 0, 0, ZoneOffset.UTC), + creationTime = OffsetDateTime.of(2018, 10, 10, 0, 0, 0, 0, ZoneOffset.UTC), + attributes = emptyList(), + tags = emptyList(), + accessTags = emptyList(), + section = extSectionWithFileList(files, fileList, referencedFiles)) + +fun extSectionWithFileList(files: List, fileList: File, referencedFiles: List) = + ExtSection( + type = "Study", + files = files.map { left(ExtFile(it.name, it, emptyList())) }, + fileList = ExtFileList("fileList", fileList, referencedFiles.map { ExtFile(it.name, it, emptyList()) })) diff --git a/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/test/SubmissionTestHelper.kt b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/test/SubmissionTestHelper.kt index b7375d4300..02c1d847db 100644 --- a/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/test/SubmissionTestHelper.kt +++ b/submission/persistence/src/test/kotlin/ac/uk/ebi/biostd/persistence/test/SubmissionTestHelper.kt @@ -7,6 +7,7 @@ import ac.uk.ebi.biostd.persistence.model.User import ebi.ac.uk.extended.model.ExtAccessTag import ebi.ac.uk.extended.model.ExtSubmission import ebi.ac.uk.extended.model.ExtTag +import ebi.ac.uk.model.SubmissionMethod import ebi.ac.uk.model.constants.ProcessingStatus.PROCESSED import org.assertj.core.api.Assertions.assertThat import java.time.OffsetDateTime @@ -17,6 +18,8 @@ internal const val SUB_ACC_NO = "Sub-Accno" internal const val SUB_TITLE = "Study" internal const val SUB_RELPATH = "/submission/relpath" internal const val SUB_ROOT_PATH = "/rootpah" +internal const val VERSION = 52 +internal val STATUS = PROCESSED internal val creationTime = OffsetDateTime.of(2018, 1, 1, 5, 10, 22, 1, ZoneOffset.UTC) internal val modificationTime = creationTime.plusDays(1) @@ -32,6 +35,8 @@ internal val extSubmission attributes = listOf(extAttribute), released = true, status = PROCESSED, + version = VERSION, + method = SubmissionMethod.FILE, modificationTime = modificationTime, releaseTime = releaseTime, creationTime = creationTime, diff --git a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/SecurityModuleConfig.kt b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/SecurityModuleConfig.kt index ffd2571678..289ff61d26 100644 --- a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/SecurityModuleConfig.kt +++ b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/SecurityModuleConfig.kt @@ -1,5 +1,6 @@ package ebi.ac.uk.security.integration +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository import ac.uk.ebi.biostd.persistence.repositories.TokenDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository @@ -27,6 +28,7 @@ class SecurityModuleConfig( private val tokenRepo: TokenDataRepository, private val groupRepository: UserGroupDataRepository, private val accessPermissionRepository: AccessPermissionRepository, + private val context: PersistenceContext, private var props: SecurityProperties ) { fun securityService(): ISecurityService = securityService @@ -40,7 +42,7 @@ class SecurityModuleConfig( private val groupService by lazy { GroupService(groupRepository, userRepo) } private val securityService by lazy { SecurityService(userRepo, securityUtil, props, profileService) } private val securityFilter by lazy { SecurityFilter(props.environment, securityService) } - private val userPrivilegesService by lazy { UserPrivilegesService(userRepo, accessPermissionRepository) } + private val userPrivilegesService by lazy { UserPrivilegesService(userRepo, context, accessPermissionRepository) } private val securityUtil by lazy { SecurityUtil(jwtParser, objectMapper, tokenRepo, userRepo, props.tokenHash) } private val objectMapper by lazy { JacksonFactory.createMapper() } diff --git a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt index f75f029f62..fb353083e9 100644 --- a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt +++ b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt @@ -1,13 +1,13 @@ package ebi.ac.uk.security.integration.components -import ebi.ac.uk.model.User - interface IUserPrivilegesService { fun canProvideAccNo(email: String): Boolean fun canSubmitProjects(email: String): Boolean - fun canResubmit(email: String, author: User, project: String?, accessTags: List): Boolean + fun canResubmit(submitter: String, accNo: String): Boolean + + fun canSubmitToProject(submitter: String, project: String): Boolean - fun canDelete(email: String, author: User, accessTags: List): Boolean + fun canDelete(submitter: String, accNo: String): Boolean } diff --git a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt index e184540c5c..0a44662ea1 100644 --- a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt +++ b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt @@ -1,38 +1,46 @@ package ebi.ac.uk.security.service +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.persistence.model.AccessType +import ac.uk.ebi.biostd.persistence.model.AccessType.ATTACH +import ac.uk.ebi.biostd.persistence.model.AccessType.UPDATE import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository -import ebi.ac.uk.model.User +import ebi.ac.uk.model.constants.SubFields.PUBLIC_ACCESS_TAG import ebi.ac.uk.security.integration.components.IUserPrivilegesService import ebi.ac.uk.security.integration.exception.UserNotFoundByEmailException internal class UserPrivilegesService( private val userRepository: UserDataRepository, - private val accessPermissionRepository: AccessPermissionRepository + private val context: PersistenceContext, + private val permissionRepository: AccessPermissionRepository ) : IUserPrivilegesService { override fun canProvideAccNo(email: String) = isSuperUser(email) override fun canSubmitProjects(email: String) = isSuperUser(email) - override fun canResubmit(email: String, author: User, project: String?, accessTags: List) = - isSuperUser(email) - .or(isAuthor(author, email).and(isNotInProject(project))) - .or(hasTag(accessTags, AccessType.SUBMIT)) + override fun canSubmitToProject(submitter: String, project: String): Boolean = + isSuperUser(submitter) + .or(permissionRepository.existsByUserEmailAndAccessTypeAndAccessTagName(submitter, ATTACH, project)) - override fun canDelete(email: String, author: User, accessTags: List) = - isSuperUser(email) - .or(isAuthor(author, email)) - .or(hasTag(accessTags, AccessType.DELETE)) + override fun canResubmit(submitter: String, accNo: String) = + isSuperUser(submitter).or(isAuthor(context.getAuthor(accNo), submitter)) + .or(hasPermissions(submitter, context.getAccessTags(accNo), UPDATE)) - private fun isNotInProject(project: String?) = project.isNullOrBlank() + override fun canDelete(submitter: String, accNo: String) = + isSuperUser(submitter) + .or(isAuthor(context.getAuthor(accNo), submitter)) + .or(hasPermissions(submitter, context.getAccessTags(accNo), AccessType.DELETE)) - private fun hasTag(accessTags: List, accessType: AccessType) = - accessPermissionRepository.existsByAccessTagNameInAndAccessType(accessTags, accessType) + private fun hasPermissions(user: String, accessTags: List, accessType: AccessType): Boolean { + val tags = accessTags.filter { it != PUBLIC_ACCESS_TAG.value } + return tags.isNotEmpty() && + tags.all { permissionRepository.existsByUserEmailAndAccessTypeAndAccessTagName(user, accessType, it) } + } private fun isSuperUser(email: String) = getUser(email).superuser - private fun isAuthor(author: User, email: String) = getUser(email).id == author.id + private fun isAuthor(author: String, email: String) = author == email private fun getUser(email: String) = userRepository.findByEmail(email).orElseThrow { UserNotFoundByEmailException(email) } diff --git a/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/UserPrivilegesServiceTest.kt b/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/UserPrivilegesServiceTest.kt index a48a907f7d..4afd8694bd 100644 --- a/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/UserPrivilegesServiceTest.kt +++ b/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/UserPrivilegesServiceTest.kt @@ -1,15 +1,16 @@ package ebi.ac.uk.security.service +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.persistence.model.AccessType import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository -import ebi.ac.uk.model.User import ebi.ac.uk.security.integration.exception.UserNotFoundByEmailException import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith @@ -17,16 +18,18 @@ import java.util.Optional import ac.uk.ebi.biostd.persistence.model.User as UserDB @ExtendWith(MockKExtension::class) +@Disabled class UserPrivilegesServiceTest( @MockK private val author: UserDB, @MockK private val otherAuthor: UserDB, @MockK private val superuser: UserDB, @MockK private val userRepository: UserDataRepository, + @MockK private val context: PersistenceContext, @MockK private val accessPermissionRepository: AccessPermissionRepository ) { - private val testAuthor = User(124, "author@mail.com", "a-secret") - private val testOtherAuthor = User(125, "otherAuthor@mail.com", "other-secret") - private val testInstance = UserPrivilegesService(userRepository, accessPermissionRepository) + private val testAuthor = "author@mail.com" + private val testOtherAuthor = "otherAuthor@mail.com" + private val testInstance = UserPrivilegesService(userRepository, context, accessPermissionRepository) @BeforeEach fun beforeEach() { @@ -47,47 +50,37 @@ class UserPrivilegesServiceTest( @Test fun `resubmit as super user`() { - assertThat(testInstance.canResubmit("superuser@mail.com", testAuthor, null, emptyList())).isTrue() - } - - @Test - fun `author user resubmits a submission that is not in a project`() { - assertThat(testInstance.canResubmit("author@mail.com", testAuthor, null, emptyList())).isTrue() - } - - @Test - fun `author user resubmits a submission that is in a project`() { - assertThat(testInstance.canResubmit("author@mail.com", testAuthor, "A-Project", emptyList())).isFalse() + assertThat(testInstance.canResubmit("superuser@mail.com", "accNo")).isTrue() } @Test fun `author user with tag resubmits a submission that is in a project`() { - assertThat(testInstance.canResubmit("author@mail.com", testAuthor, "A-Project", listOf("A-Project"))).isTrue() + assertThat(testInstance.canResubmit("author@mail.com", "accNo")).isTrue() } @Test fun `super user deletes a submission`() { - assertThat(testInstance.canDelete("superuser@mail.com", testAuthor, emptyList())).isTrue() + assertThat(testInstance.canDelete("superuser@mail.com", "accNo")).isTrue() } @Test fun `author user deletes own submission`() { - assertThat(testInstance.canDelete("author@mail.com", testAuthor, emptyList())).isTrue() + assertThat(testInstance.canDelete("author@mail.com", "accNo")).isTrue() } @Test fun `author user deletes not own submission`() { - assertThat(testInstance.canDelete("author@mail.com", testOtherAuthor, emptyList())).isFalse() + assertThat(testInstance.canDelete("author@mail.com", "accNo")).isFalse() } @Test fun `other author user deletes submission with tag`() { - assertThat(testInstance.canDelete("otherAuthor@mail.com", testAuthor, listOf("A-Project"))).isTrue() + assertThat(testInstance.canDelete("otherAuthor@mail.com", "accNo")).isTrue() } @Test fun `other author user deletes submission without tag`() { - assertThat(testInstance.canDelete("otherAuthor@mail.com", testAuthor, emptyList())).isFalse() + assertThat(testInstance.canDelete("otherAuthor@mail.com", "accNo")).isFalse() } @Test diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/query/ProjectsListTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/query/ProjectsListTest.kt index f8f4a68425..3ace4b4518 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/query/ProjectsListTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/query/ProjectsListTest.kt @@ -1,17 +1,18 @@ package ac.uk.ebi.biostd.itest.test.project.query +import ac.uk.ebi.biostd.client.integration.commons.SubmissionFormat import ac.uk.ebi.biostd.client.integration.web.BioWebClient import ac.uk.ebi.biostd.itest.common.BaseIntegrationTest import ac.uk.ebi.biostd.itest.entities.SuperUser import ac.uk.ebi.biostd.persistence.model.AccessPermission import ac.uk.ebi.biostd.persistence.model.AccessType import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository +import ebi.ac.uk.api.dto.NonRegistration import ebi.ac.uk.asserts.assertThat import ebi.ac.uk.dsl.line import ebi.ac.uk.dsl.tsv -import ebi.ac.uk.test.createFile import io.github.glytching.junit.extension.folder.TemporaryFolder import io.github.glytching.junit.extension.folder.TemporaryFolderExtension import org.assertj.core.api.Assertions.assertThat @@ -26,14 +27,14 @@ import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.junit.jupiter.SpringExtension @ExtendWith(TemporaryFolderExtension::class) -internal class ProjectsListTest(private val tempFolder: TemporaryFolder) : BaseIntegrationTest(tempFolder) { +internal class ProjectsListTest(tempFolder: TemporaryFolder) : BaseIntegrationTest(tempFolder) { @Nested @ExtendWith(SpringExtension::class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @DirtiesContext inner class ProjectListTest( @Autowired val userDataRepository: UserDataRepository, - @Autowired val tagsDataRepository: AccessTagDataRepository, + @Autowired val tagsDataRepository: AccessTagDataRepo, @Autowired val accessPermissionRepository: AccessPermissionRepository ) { @LocalServerPort @@ -65,10 +66,9 @@ internal class ProjectsListTest(private val tempFolder: TemporaryFolder) : BaseI line() line("Project") - } + }.toString() - val projectFile = tempFolder.createFile("project.tsv", project.toString()) - assertThat(webClient.submitProject(projectFile)).isSuccessful() + assertThat(webClient.submitSingle(project, SubmissionFormat.TSV, NonRegistration)).isSuccessful() // TODO add operation to provide permissions accessPermissionRepository.save(AccessPermission( diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/submit/ProjectSubmitTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/submit/ProjectSubmitTest.kt index d0465f6bcb..44aed20025 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/submit/ProjectSubmitTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/project/submit/ProjectSubmitTest.kt @@ -1,19 +1,19 @@ package ac.uk.ebi.biostd.itest.test.project.submit +import ac.uk.ebi.biostd.client.integration.commons.SubmissionFormat import ac.uk.ebi.biostd.client.integration.web.BioWebClient import ac.uk.ebi.biostd.common.config.PersistenceConfig import ac.uk.ebi.biostd.itest.common.BaseIntegrationTest import ac.uk.ebi.biostd.itest.entities.SuperUser -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.SequenceDataRepository import ac.uk.ebi.biostd.persistence.service.SubmissionRepository import ebi.ac.uk.asserts.assertThat import ebi.ac.uk.dsl.line import ebi.ac.uk.dsl.tsv import ebi.ac.uk.model.constants.ProcessingStatus.PROCESSED -import ebi.ac.uk.model.extensions.attachTo import ebi.ac.uk.model.extensions.title -import ebi.ac.uk.test.createFile +import ebi.ac.uk.util.collections.second import io.github.glytching.junit.extension.folder.TemporaryFolder import io.github.glytching.junit.extension.folder.TemporaryFolderExtension import org.assertj.core.api.Assertions.assertThat @@ -36,7 +36,7 @@ internal class ProjectSubmitTest(private val tempFolder: TemporaryFolder) : Base @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @DirtiesContext inner class ProjectSubmitTest( - @Autowired val tagsDataRepository: AccessTagDataRepository, + @Autowired val tagsDataRepository: AccessTagDataRepo, @Autowired val submissionRepository: SubmissionRepository, @Autowired val sequenceRepository: SequenceDataRepository ) { @@ -51,53 +51,55 @@ internal class ProjectSubmitTest(private val tempFolder: TemporaryFolder) : Base } @Test - fun `submit project`() { - val project = tsv { - line("Submission", "AProject") - line("Title", "A Project") - line("AccNoTemplate", "!{S-APR}") + fun `submit private project`() { + val privateProject = tsv { + line("Submission", "PrivateProject") + line("Title", "A Private Project") + line("AccNoTemplate", "!{S-PRP}") line() line("Project") - } + }.toString() - val projectFile = tempFolder.createFile("a-project.tsv", project.toString()) - assertThat(webClient.submitProject(projectFile)).isSuccessful() + assertThat(webClient.submitSingle(privateProject, SubmissionFormat.TSV)).isSuccessful() - val submittedProject = submissionRepository.getExtendedByAccNo("AProject") - assertThat(submittedProject.accNo).isEqualTo("AProject") - assertThat(submittedProject.title).isEqualTo("A Project") + val submittedProject = submissionRepository.getExtendedByAccNo("PrivateProject") + assertThat(submittedProject.accNo).isEqualTo("PrivateProject") + assertThat(submittedProject.title).isEqualTo("A Private Project") assertThat(submittedProject.processingStatus).isEqualTo(PROCESSED) assertThat(submittedProject.accessTags).hasSize(1) - assertThat(submittedProject.accessTags.first()).isEqualTo("AProject") + assertThat(submittedProject.accessTags.first()).isEqualTo("PrivateProject") - assertThat(tagsDataRepository.existsByName("AProject")).isTrue() - assertThat(sequenceRepository.existsByPrefix("S-APR")).isTrue() + assertThat(tagsDataRepository.existsByName("PrivateProject")).isTrue() + assertThat(sequenceRepository.existsByPrefix("S-PRP")).isTrue() } @Test - fun `attach submission to a project`() { - val project = tsv { - line("Submission", "A-Project") - line("AccNoTemplate", "!{S-APR}") + fun `submit public project`() { + val publicProject = tsv { + line("Submission", "PublicProject") + line("Title", "Public Project") + line("AccNoTemplate", "!{S-PUP}") + line("ReleaseDate", "2015-06-09") line() line("Project") }.toString() - val submission = tempFolder.createFile("submission.tsv", tsv { - line("Submission", "S-TEST4") - line("Title", "Attached Submission") - }.toString()) + assertThat(webClient.submitSingle(publicProject, SubmissionFormat.TSV)).isSuccessful() - assertThat(webClient.submitProject(tempFolder.createFile("project.tsv", project))).isSuccessful() + val submittedProject = submissionRepository.getExtendedByAccNo("PublicProject") + assertThat(submittedProject.accNo).isEqualTo("PublicProject") + assertThat(submittedProject.title).isEqualTo("Public Project") + assertThat(submittedProject.processingStatus).isEqualTo(PROCESSED) - val response = webClient.attachSubmission("A-Project", submission, listOf()) - assertThat(response).isSuccessful() + assertThat(submittedProject.accessTags).hasSize(2) + assertThat(submittedProject.accessTags.first()).isEqualTo("PublicProject") + assertThat(submittedProject.accessTags.second()).isEqualTo("Public") - val savedSubmission = submissionRepository.getByAccNo("S-TEST4") - assertThat(savedSubmission.attachTo).isEqualTo("A-Project") + assertThat(tagsDataRepository.existsByName("PublicProject")).isTrue() + assertThat(sequenceRepository.existsByPrefix("S-PUP")).isTrue() } } } diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/DeletePermissionTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/DeletePermissionTest.kt index 6076da9522..2e14e96b8f 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/DeletePermissionTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/DeletePermissionTest.kt @@ -10,7 +10,7 @@ import ac.uk.ebi.biostd.itest.entities.SuperUser import ac.uk.ebi.biostd.persistence.model.AccessPermission import ac.uk.ebi.biostd.persistence.model.AccessType.DELETE import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository import ac.uk.ebi.biostd.persistence.service.SubmissionRepository import ebi.ac.uk.asserts.assertThat @@ -42,7 +42,7 @@ internal class DeletePermissionTest(private val tempFolder: TemporaryFolder) : B inner class DeleteSubmissionTest( @Autowired private val userDataRepository: UserDataRepository, @Autowired private val submissionRepository: SubmissionRepository, - @Autowired private val tagsDataRepository: AccessTagDataRepository, + @Autowired private val tagsDataRepository: AccessTagDataRepo, @Autowired private val accessPermissionRepository: AccessPermissionRepository ) { @LocalServerPort @@ -113,8 +113,9 @@ internal class DeletePermissionTest(private val tempFolder: TemporaryFolder) : B line("Project") }.toString() + val projectFile = tempFolder.createFile("a-project.tsv", project) - assertThat(superUserWebClient.submitProject(tempFolder.createFile("a-project.tsv", project))).isSuccessful() + assertThat(superUserWebClient.submitSingle(projectFile, emptyList())).isSuccessful() val accessTag = tagsDataRepository.findByName("AProject") val user = userDataRepository.findByEmailAndActive(RegularUser.email, active = true) diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/SubmitPermissionTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/SubmitPermissionTest.kt index 1ef1fd3307..5a51d3ef0c 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/SubmitPermissionTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/security/SubmitPermissionTest.kt @@ -11,7 +11,7 @@ import ac.uk.ebi.biostd.persistence.model.AccessPermission import ac.uk.ebi.biostd.persistence.model.AccessType.ATTACH import ac.uk.ebi.biostd.persistence.model.AccessType.SUBMIT import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository import ebi.ac.uk.asserts.assertThat import ebi.ac.uk.dsl.line @@ -21,6 +21,7 @@ import io.github.glytching.junit.extension.folder.TemporaryFolder import io.github.glytching.junit.extension.folder.TemporaryFolderExtension import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -40,7 +41,7 @@ internal class SubmitPermissionTest(private val tempFolder: TemporaryFolder) : B @DirtiesContext inner class SubmitProjectTest( @Autowired private val userDataRepository: UserDataRepository, - @Autowired private val tagsDataRepository: AccessTagDataRepository, + @Autowired private val tagsDataRepository: AccessTagDataRepo, @Autowired private val accessPermissionRepository: AccessPermissionRepository ) { @LocalServerPort @@ -67,13 +68,13 @@ internal class SubmitPermissionTest(private val tempFolder: TemporaryFolder) : B @Test fun `create project with superuser`() { - assertThat(superUserWebClient.submitProject(projectFile)).isSuccessful() + assertThat(superUserWebClient.submitSingle(projectFile, emptyList())).isSuccessful() } @Test fun `create project with regular user`() { assertThatExceptionOfType(WebClientException::class.java).isThrownBy { - regularUserWebClient.submitProject(projectFile) + regularUserWebClient.submitSingle(projectFile, emptyList()) } } @@ -93,14 +94,19 @@ internal class SubmitPermissionTest(private val tempFolder: TemporaryFolder) : B line("Title", "Test Submission") }.toString() - assertThat(superUserWebClient.submitProject(tempFolder.createFile("test.tsv", project))).isSuccessful() + val projectFile = tempFolder.createFile("test.tsv", project) + + assertThat(superUserWebClient.submitSingle(projectFile, emptyList())).isSuccessful() assertThatExceptionOfType(WebClientException::class.java).isThrownBy { regularUserWebClient.submitSingle(submission, SubmissionFormat.TSV) } } + @Disabled @Test fun `submit with attach permission access tag`() { + // TODO discuss whether or not this will be a case that will be covered + // TODO discuss whther or not access tags will be supported or removed val project = tsv { line("Submission", "TestProject2") line("AccNoTemplate", "!{S-TPRJ}") @@ -115,7 +121,9 @@ internal class SubmitPermissionTest(private val tempFolder: TemporaryFolder) : B line("Title", "Test Submission") }.toString() - assertThat(superUserWebClient.submitProject(tempFolder.createFile("test2.tsv", project))).isSuccessful() + val projectFile = tempFolder.createFile("test2.tsv", project) + + assertThat(superUserWebClient.submitSingle(projectFile, emptyList())).isSuccessful() val accessTag = tagsDataRepository.findByName("TestProject2") val user = userDataRepository.findByEmailAndActive(RegularUser.email, active = true) diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt index de4ccb7fb5..fe40b0fc23 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt @@ -8,6 +8,8 @@ import ac.uk.ebi.biostd.itest.entities.SuperUser import ebi.ac.uk.asserts.assertThat import ebi.ac.uk.dsl.line import ebi.ac.uk.dsl.tsv +import ebi.ac.uk.model.SubmissionMethod +import ebi.ac.uk.test.createFile import io.github.glytching.junit.extension.folder.TemporaryFolder import io.github.glytching.junit.extension.folder.TemporaryFolderExtension import org.assertj.core.api.Assertions.assertThat @@ -22,13 +24,13 @@ import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.junit.jupiter.SpringExtension @ExtendWith(TemporaryFolderExtension::class) -internal class SubmissionListApiTest(tempFolder: TemporaryFolder) : BaseIntegrationTest(tempFolder) { +internal class SubmissionListApiTest(private val tempFolder: TemporaryFolder) : BaseIntegrationTest(tempFolder) { @Nested @Import(PersistenceConfig::class) @ExtendWith(SpringExtension::class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @DirtiesContext - inner class SingleSubmissionTest() { + inner class SingleSubmissionTest { @LocalServerPort private var serverPort: Int = 0 @@ -38,14 +40,13 @@ internal class SubmissionListApiTest(tempFolder: TemporaryFolder) : BaseIntegrat fun init() { webClient = getWebClient(serverPort, SuperUser) - for (idx in 11..30) { - val submission = tsv { - line("Submission", "SimpleAcc$idx") - line("Title", "Simple Submission $idx - keyword$idx") - line("ReleaseDate", "2019-09-$idx") - line() - }.toString() - assertThat(webClient.submitSingle(submission, SubmissionFormat.TSV)).isSuccessful() + for (idx in 11..20) { + assertThat(webClient.submitSingle(getSimpleSubmission(idx), SubmissionFormat.TSV)).isSuccessful() + } + + for (idx in 21..30) { + val submission = tempFolder.createFile("submission$idx.tsv", getSimpleSubmission(idx)) + assertThat(webClient.submitSingle(submission, emptyList())).isSuccessful() } } @@ -66,6 +67,20 @@ internal class SubmissionListApiTest(tempFolder: TemporaryFolder) : BaseIntegrat assertThat(submissionList).hasOnlyOneElementSatisfying { assertThat(it.accno).isEqualTo("SimpleAcc17") assertThat(it.version).isEqualTo(1) + assertThat(it.method).isEqualTo(SubmissionMethod.PAGE_TAB) + } + } + + @Test + fun `get direct submission list by accession`() { + val submissionList = webClient.getSubmissions(mapOf( + "accNo" to "SimpleAcc27" + )) + + assertThat(submissionList).hasOnlyOneElementSatisfying { + assertThat(it.accno).isEqualTo("SimpleAcc27") + assertThat(it.version).isEqualTo(1) + assertThat(it.method).isEqualTo(SubmissionMethod.FILE) } } @@ -98,5 +113,12 @@ internal class SubmissionListApiTest(tempFolder: TemporaryFolder) : BaseIntegrat assertThat(submissionList).hasSize(5) } + + private fun getSimpleSubmission(idx: Int) = tsv { + line("Submission", "SimpleAcc$idx") + line("Title", "Simple Submission $idx - keyword$idx") + line("ReleaseDate", "2019-09-$idx") + line() + }.toString() } } diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/SubmissionToProjectsTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/SubmissionToProjectsTest.kt index c25fd29eda..965e8a0045 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/SubmissionToProjectsTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/SubmissionToProjectsTest.kt @@ -190,10 +190,9 @@ internal class SubmissionToProjectsTest(private val tempFolder: TemporaryFolder) line("Project") }.toString() - // TODO these won't need to be files once the refactor to the model is merged - assertThat(webClient.submitProject(tempFolder.createFile("test.tsv", testProject))).isSuccessful() - assertThat(webClient.submitProject(tempFolder.createFile("public.tsv", publicProject))).isSuccessful() - assertThat(webClient.submitProject(tempFolder.createFile("private.tsv", privateProject))).isSuccessful() + assertThat(webClient.submitSingle(testProject, SubmissionFormat.TSV)).isSuccessful() + assertThat(webClient.submitSingle(publicProject, SubmissionFormat.TSV)).isSuccessful() + assertThat(webClient.submitSingle(privateProject, SubmissionFormat.TSV)).isSuccessful() } } } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/PersistenceConfig.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/PersistenceConfig.kt index 470b304023..d801de62fb 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/PersistenceConfig.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/PersistenceConfig.kt @@ -1,9 +1,13 @@ package ac.uk.ebi.biostd.common.config +import ac.uk.ebi.biostd.common.property.ApplicationProperties +import ac.uk.ebi.biostd.integration.SerializationService import ac.uk.ebi.biostd.persistence.integration.PersistenceContextImpl import ac.uk.ebi.biostd.persistence.mapping.SubmissionDbMapper import ac.uk.ebi.biostd.persistence.mapping.SubmissionMapper -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.mapping.extended.from.ToDbSubmissionMapper +import ac.uk.ebi.biostd.persistence.mapping.extended.to.ToExtSubmissionMapper +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.repositories.JdbcLockExecutor import ac.uk.ebi.biostd.persistence.repositories.LockExecutor import ac.uk.ebi.biostd.persistence.repositories.SequenceDataRepository @@ -11,9 +15,11 @@ import ac.uk.ebi.biostd.persistence.repositories.SubmissionDataRepository import ac.uk.ebi.biostd.persistence.repositories.TagDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository +import ac.uk.ebi.biostd.persistence.service.FilePersistenceService import ac.uk.ebi.biostd.persistence.service.ProjectRepository import ac.uk.ebi.biostd.persistence.service.SubmissionRepository import com.cosium.spring.data.jpa.entity.graph.repository.support.EntityGraphJpaRepositoryFactoryBean +import ebi.ac.uk.paths.SubmissionFolderResolver import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -27,12 +33,25 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate class PersistenceConfig( private val submissionDataRepository: SubmissionDataRepository, private val sequenceRepository: SequenceDataRepository, - private val tagsDataRepository: AccessTagDataRepository, + private val tagsDataRepository: AccessTagDataRepo, private val tagsRefRepository: TagDataRepository, private val userRepository: UserDataRepository, private val template: NamedParameterJdbcTemplate, - private val userDataRepository: UserDataDataRepository + private val userDataRepository: UserDataDataRepository, + private val applicationProperties: ApplicationProperties, + private val folderResolver: SubmissionFolderResolver, + private val serializationService: SerializationService ) { + @Bean + fun toDbSubmissionMapper( + tagsRepo: AccessTagDataRepo, + tagsRefRepo: TagDataRepository, + userRepo: UserDataRepository + ) = ToDbSubmissionMapper(tagsRepo, tagsRefRepo, userRepo) + + @Bean + fun toExtSubmissionMapper() = ToExtSubmissionMapper(applicationProperties.submissionsPath) + @Bean fun submissionRepository() = SubmissionRepository(submissionDataRepository, submissionDbMapper()) @@ -45,19 +64,28 @@ class PersistenceConfig( @Bean fun submissionMapper() = SubmissionMapper(tagsDataRepository, tagsRefRepository, userRepository) + @Bean + fun filePersistenceService() = FilePersistenceService(folderResolver, serializationService) + @Bean @ConditionalOnMissingBean(LockExecutor::class) fun lockExecutor(): LockExecutor = JdbcLockExecutor(template) @Bean - fun persistenceContext(lockExecutor: LockExecutor) = + fun persistenceContext( + lockExecutor: LockExecutor, + dbSubmissionMapper: ToDbSubmissionMapper, + toExtSubmissionMapper: ToExtSubmissionMapper, + filePersistenceService: FilePersistenceService + ) = PersistenceContextImpl( submissionDataRepository, sequenceRepository, tagsDataRepository, lockExecutor, - submissionDbMapper(), - submissionMapper(), - userDataRepository + userDataRepository, + dbSubmissionMapper, + toExtSubmissionMapper, + filePersistenceService ) } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SecurityConfig.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SecurityConfig.kt index 49d3e2e531..3cc1a0b9f9 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SecurityConfig.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SecurityConfig.kt @@ -1,6 +1,7 @@ package ac.uk.ebi.biostd.common.config import ac.uk.ebi.biostd.common.property.ApplicationProperties +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository import ac.uk.ebi.biostd.persistence.repositories.TokenDataRepository import ac.uk.ebi.biostd.persistence.repositories.UserDataRepository @@ -72,12 +73,13 @@ class SecurityBeansConfig(private val objectMapper: ObjectMapper, properties: Ap @Bean fun securityModuleConfig( + context: PersistenceContext, userRepository: UserDataRepository, tokenRepository: TokenDataRepository, groupRepository: UserGroupDataRepository, accessPermissionRepository: AccessPermissionRepository ): SecurityModuleConfig = SecurityModuleConfig( - userRepository, tokenRepository, groupRepository, accessPermissionRepository, securityProps) + userRepository, tokenRepository, groupRepository, accessPermissionRepository, context, securityProps) @Bean fun securityService(securityConfig: SecurityModuleConfig): ISecurityService = securityConfig.securityService() diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionConfig.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionConfig.kt index 83d2a7d364..6e6bb62a43 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionConfig.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionConfig.kt @@ -2,17 +2,14 @@ package ac.uk.ebi.biostd.common.config import ac.uk.ebi.biostd.integration.SerializationService import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.service.ProjectRepository import ac.uk.ebi.biostd.persistence.service.SubmissionRepository import ac.uk.ebi.biostd.submission.domain.helpers.SourceGenerator import ac.uk.ebi.biostd.submission.domain.service.ProjectService import ac.uk.ebi.biostd.submission.domain.service.SubmissionService import ac.uk.ebi.biostd.submission.submitter.SubmissionSubmitter -import ac.uk.ebi.biostd.submission.submitter.ProjectSubmitter -import ac.uk.ebi.biostd.submission.web.handlers.ProjectWebHandler import ac.uk.ebi.biostd.submission.web.handlers.SubmissionWebHandler -import ebi.ac.uk.persistence.PersistenceContext import ebi.ac.uk.security.integration.components.IUserPrivilegesService import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -28,26 +25,19 @@ class SubmissionConfig( fun submissionService( subRepository: SubmissionRepository, serializationService: SerializationService, - persistenceContext: PersistenceContext, userPrivilegeService: IUserPrivilegesService, submissionSubmitter: SubmissionSubmitter ): SubmissionService = SubmissionService( - subRepository, persistenceContext, serializationService, userPrivilegeService, submissionSubmitter) + subRepository, serializationService, userPrivilegeService, submissionSubmitter) @Bean fun projectService( - projectSubmitter: ProjectSubmitter, - tagsDataRepository: AccessTagDataRepository, + tagsDataRepository: AccessTagDataRepo, projectRepository: ProjectRepository, accessPermissionRepository: AccessPermissionRepository - ): ProjectService = ProjectService( - projectSubmitter, tagsDataRepository, projectRepository, accessPermissionRepository) + ): ProjectService = ProjectService(tagsDataRepository, projectRepository, accessPermissionRepository) @Bean fun submissionHandler(submissionService: SubmissionService): SubmissionWebHandler = SubmissionWebHandler(submissionService, sourceGenerator, serializationService) - - @Bean - fun projectHandler(projectService: ProjectService) = - ProjectWebHandler(projectService, serializationService) } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmitterConfig.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmitterConfig.kt index 71b1f5f6a6..57e8fb06dc 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmitterConfig.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmitterConfig.kt @@ -4,18 +4,14 @@ import ac.uk.ebi.biostd.common.config.SubmitterConfig.FilesHandlerConfig import ac.uk.ebi.biostd.common.config.SubmitterConfig.ServiceConfig import ac.uk.ebi.biostd.common.property.ApplicationProperties import ac.uk.ebi.biostd.integration.SerializationConfig -import ac.uk.ebi.biostd.submission.handlers.FilesCopier -import ac.uk.ebi.biostd.submission.handlers.FilesHandler -import ac.uk.ebi.biostd.submission.handlers.FilesValidator -import ac.uk.ebi.biostd.submission.handlers.OutputFilesGenerator +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.submission.service.AccNoService -import ac.uk.ebi.biostd.submission.submitter.SubmissionSubmitter +import ac.uk.ebi.biostd.submission.service.ParentInfoService +import ac.uk.ebi.biostd.submission.service.ProjectInfoService import ac.uk.ebi.biostd.submission.service.TimesService -import ac.uk.ebi.biostd.submission.service.ProjectValidationService -import ac.uk.ebi.biostd.submission.submitter.ProjectSubmitter +import ac.uk.ebi.biostd.submission.submitter.SubmissionSubmitter import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil import ebi.ac.uk.paths.SubmissionFolderResolver -import ebi.ac.uk.persistence.PersistenceContext import ebi.ac.uk.security.integration.components.IUserPrivilegesService import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -28,19 +24,12 @@ import java.nio.file.Paths class SubmitterConfig { @Bean fun submissionSubmitter( - filesHandler: FilesHandler, timesService: TimesService, accNoService: AccNoService, + parentInfoService: ParentInfoService, + projectInfoService: ProjectInfoService, persistenceContext: PersistenceContext - ) = SubmissionSubmitter(filesHandler, timesService, accNoService, persistenceContext) - - @Bean - fun projectSubmitter( - timesService: TimesService, - accNoPatternUtil: AccNoPatternUtil, - persistenceContext: PersistenceContext, - projectValidationService: ProjectValidationService - ) = ProjectSubmitter(timesService, accNoPatternUtil, persistenceContext, projectValidationService) + ) = SubmissionSubmitter(timesService, accNoService, parentInfoService, projectInfoService, persistenceContext) @Configuration class FilesHandlerConfig(private val appProperties: ApplicationProperties) { @@ -50,18 +39,6 @@ class SubmitterConfig { @Bean fun serializationService() = SerializationConfig.serializationService() - - @Bean - fun filesHandler() = FilesHandler(filesValidator(), filesCopier(), outputFilesGenerator()) - - @Bean - fun outputFilesGenerator() = OutputFilesGenerator(folderResolver(), serializationService()) - - @Bean - fun filesCopier() = FilesCopier(folderResolver()) - - @Bean - fun filesValidator() = FilesValidator() } @Configuration @@ -77,7 +54,10 @@ class SubmitterConfig { fun accNoService() = AccNoService(context, accNoPatternUtil(), userPrivilegesService) @Bean - fun projectValidationService() = ProjectValidationService(context, accNoPatternUtil(), userPrivilegesService) + fun parentInfoService() = ParentInfoService(context) + + @Bean + fun projectInfoService() = ProjectInfoService(context, accNoPatternUtil(), userPrivilegesService) @Bean fun timesService() = TimesService(context) diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/property/ApplicationProperties.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/property/ApplicationProperties.kt index c621ec88e0..a5b66f8e35 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/property/ApplicationProperties.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/property/ApplicationProperties.kt @@ -4,12 +4,17 @@ import ebi.ac.uk.notifications.integration.NotificationProperties import ebi.ac.uk.security.integration.SecurityProperties import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.NestedConfigurationProperty +import java.nio.file.Path +import java.nio.file.Paths @ConfigurationProperties(prefix = "app") open class ApplicationProperties { lateinit var basepath: String lateinit var tempDirPath: String + val submissionsPath: Path + get() = Paths.get(basepath).resolve("submissions") + @NestedConfigurationProperty var security: SecurityProperties = SecurityProperties() diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/ProjectService.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/ProjectService.kt index 92619c8590..56cbfc4bc9 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/ProjectService.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/ProjectService.kt @@ -3,24 +3,16 @@ package ac.uk.ebi.biostd.submission.domain.service import ac.uk.ebi.biostd.persistence.model.AccessTag import ac.uk.ebi.biostd.persistence.model.AccessType import ac.uk.ebi.biostd.persistence.repositories.AccessPermissionRepository -import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepository +import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo import ac.uk.ebi.biostd.persistence.service.ProjectRepository -import ac.uk.ebi.biostd.submission.submitter.ProjectSubmitter -import ebi.ac.uk.model.ExtendedSubmission import ebi.ac.uk.model.Project -import ebi.ac.uk.model.Submission -import ebi.ac.uk.model.extensions.title import ebi.ac.uk.security.integration.model.api.SecurityUser class ProjectService( - private val submitter: ProjectSubmitter, - private val tagsDataRepository: AccessTagDataRepository, + private val tagsDataRepository: AccessTagDataRepo, private val projectRepository: ProjectRepository, private val accessPermissionRepository: AccessPermissionRepository ) { - fun submit(project: Submission, user: SecurityUser) = - submitter.submit(ExtendedSubmission(project, user.asUser())) - fun getAllowedProjects(user: SecurityUser, accessType: AccessType): List { val accessTags = if (user.superuser) tagsDataRepository.findAll() else getUserTags(user, accessType) return projectRepository.findProjectsByAccessTags(accessTags).map { Project(it.accNo, it.title) } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionService.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionService.kt index 7194d819b0..d8df94f3da 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionService.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionService.kt @@ -10,13 +10,11 @@ import ac.uk.ebi.biostd.persistence.service.SubmissionRepository import ac.uk.ebi.biostd.submission.model.SubmissionRequest import ac.uk.ebi.biostd.submission.submitter.SubmissionSubmitter import ebi.ac.uk.model.Submission -import ebi.ac.uk.persistence.PersistenceContext import ebi.ac.uk.security.integration.components.IUserPrivilegesService import ebi.ac.uk.security.integration.model.api.SecurityUser class SubmissionService( private val submissionRepository: SubmissionRepository, - private val persistenceContext: PersistenceContext, private val serializationService: SerializationService, private val userPrivilegesService: IUserPrivilegesService, private val submissionSubmitter: SubmissionSubmitter @@ -40,9 +38,7 @@ class SubmissionService( submissionRepository.getSubmissionsByUser(user.id, filter) fun deleteSubmission(accNo: String, user: SecurityUser) { - val submission = persistenceContext.getSubmission(accNo)!! - - require(userPrivilegesService.canDelete(user.email, submission.user, submission.accessTags)) + require(userPrivilegesService.canDelete(user.email, accNo)) submissionRepository.expireSubmission(accNo) } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/handlers/ProjectWebHandler.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/handlers/ProjectWebHandler.kt deleted file mode 100644 index ef257146bb..0000000000 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/handlers/ProjectWebHandler.kt +++ /dev/null @@ -1,17 +0,0 @@ -package ac.uk.ebi.biostd.submission.web.handlers - -import ac.uk.ebi.biostd.integration.SerializationService -import ac.uk.ebi.biostd.submission.domain.service.ProjectService -import ebi.ac.uk.model.Submission -import ebi.ac.uk.security.integration.model.api.SecurityUser -import java.io.File - -class ProjectWebHandler( - private val projectService: ProjectService, - private val serializationService: SerializationService -) { - fun submit(user: SecurityUser, projectFile: File): Submission { - val project = serializationService.deserializeSubmission(projectFile) - return projectService.submit(project, user) - } -} diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/ProjectResource.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/ProjectResource.kt index 178c7de7f4..b32ffed649 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/ProjectResource.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/ProjectResource.kt @@ -3,43 +3,22 @@ package ac.uk.ebi.biostd.submission.web.resources import ac.uk.ebi.biostd.persistence.model.AccessType import ac.uk.ebi.biostd.submission.converters.BioUser import ac.uk.ebi.biostd.submission.domain.service.ProjectService -import ac.uk.ebi.biostd.submission.domain.service.TempFileGenerator -import ac.uk.ebi.biostd.submission.web.handlers.ProjectWebHandler -import ac.uk.ebi.biostd.submission.web.handlers.SubmissionWebHandler import ebi.ac.uk.model.Project -import ebi.ac.uk.model.Submission -import ebi.ac.uk.model.constants.FILES -import ebi.ac.uk.model.constants.MULTIPART_FORM_DATA -import ebi.ac.uk.model.constants.PROJECT -import ebi.ac.uk.model.constants.SUBMISSION import ebi.ac.uk.security.integration.model.api.SecurityUser import io.swagger.annotations.Api import io.swagger.annotations.ApiImplicitParam import io.swagger.annotations.ApiOperation -import io.swagger.annotations.ApiParam -import org.springframework.http.HttpHeaders -import org.springframework.http.MediaType.APPLICATION_JSON_VALUE import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.ResponseBody import org.springframework.web.bind.annotation.RestController -import org.springframework.web.multipart.MultipartFile @RestController @RequestMapping("/projects") @PreAuthorize("isAuthenticated()") @Api(tags = ["Projects"]) -class ProjectResource( - private val projectService: ProjectService, - private val tmpFileGenerator: TempFileGenerator, - private val projectWebHandler: ProjectWebHandler, - private val tempFileGenerator: TempFileGenerator, - private val submissionWebHandler: SubmissionWebHandler -) { +class ProjectResource(private val projectService: ProjectService) { @GetMapping @ResponseBody @ApiOperation("Get the list of available projects for the current user") @@ -47,36 +26,4 @@ class ProjectResource( fun getUserProjects( @BioUser user: SecurityUser ): List = projectService.getAllowedProjects(user, AccessType.ATTACH) - - @PostMapping(headers = ["${HttpHeaders.CONTENT_TYPE}=$MULTIPART_FORM_DATA"], produces = [APPLICATION_JSON_VALUE]) - @ResponseBody - @ApiOperation("Register a new project") - @ApiImplicitParam(name = "X-Session-Token", value = "User authentication token", required = true) - fun submit( - @BioUser user: SecurityUser, - - @ApiParam(name = "Project File", value = "File containing the project page tab definition") - @RequestParam(PROJECT) file: MultipartFile - ): Submission = projectWebHandler.submit(user, tmpFileGenerator.asFile(file)) - - @PostMapping( - value = ["/{accNo}/submissions"], - headers = ["${HttpHeaders.CONTENT_TYPE}=$MULTIPART_FORM_DATA"], - produces = [APPLICATION_JSON_VALUE]) - @ResponseBody - @ApiOperation("Attach the submission to the project with the given accession") - @ApiImplicitParam(name = "X-Session-Token", value = "User authentication token", required = true) - fun attachSubmission( - @BioUser user: SecurityUser, - - @ApiParam(name = "AccNo", value = "Parent project accession") - @PathVariable accNo: String, - - @ApiParam(name = "Submission File", value = "File containing the submission page tab definition") - @RequestParam(SUBMISSION) file: MultipartFile, - - @ApiParam(name = "Files", value = "Files included in the submission") - @RequestParam(FILES) files: Array - ): Submission = - submissionWebHandler.submit(user, tempFileGenerator.asFile(file), tempFileGenerator.asFiles(files), accNo) } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionResource.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionResource.kt index f3a1207608..bad68a91a7 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionResource.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionResource.kt @@ -73,5 +73,5 @@ class SubmissionResource( ): List = submissionWebHandler.getSubmissions(user, filter).map { it.asDto() } private fun SimpleSubmission.asDto() = - SubmissionDto(accNo, title.orEmpty(), version, creationTime, modificationTime, releaseTime) + SubmissionDto(accNo, title.orEmpty(), version, creationTime, modificationTime, releaseTime, method) } diff --git a/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/submission/web/handlers/ProjectWebHandlerTest.kt b/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/submission/web/handlers/ProjectWebHandlerTest.kt deleted file mode 100644 index 9621bad419..0000000000 --- a/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/submission/web/handlers/ProjectWebHandlerTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -package ac.uk.ebi.biostd.submission.web.handlers - -import ac.uk.ebi.biostd.integration.SerializationService -import ac.uk.ebi.biostd.submission.domain.service.ProjectService -import ebi.ac.uk.dsl.submission -import ebi.ac.uk.security.integration.model.api.SecurityUser -import io.github.glytching.junit.extension.folder.TemporaryFolder -import io.github.glytching.junit.extension.folder.TemporaryFolderExtension -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.verify -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(TemporaryFolderExtension::class, MockKExtension::class) -class ProjectWebHandlerTest( - temporaryFolder: TemporaryFolder, - @MockK private val user: SecurityUser, - @MockK private val projectService: ProjectService, - @MockK private val serializationService: SerializationService -) { - private val project = submission("A-Project") { } - private val projectFile = temporaryFolder.createFile("submission.tsv") - private val testInstance = ProjectWebHandler(projectService, serializationService) - - @BeforeEach - fun beforeEach() { - every { projectService.submit(project, user) } returns project - every { serializationService.deserializeSubmission(projectFile) } returns project - } - - @Test - fun submit() { - testInstance.submit(user, projectFile) - - verify(exactly = 1) { - projectService.submit(project, user) - serializationService.deserializeSubmission(projectFile) - } - } -} diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt index 2eeb2e687b..4f67579565 100644 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt +++ b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt @@ -1,18 +1,15 @@ package ac.uk.ebi.biostd.submission.exceptions -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.User - /** * Generated when user is not allowed to perform an operation. */ sealed class InvalidPermissionsException(message: String) : RuntimeException(message) -class ProvideAccessNumber(user: User) : InvalidPermissionsException( - "{${user.email}} is not allowed to provide accession number directly") +class ProvideAccessNumber(user: String) : InvalidPermissionsException( + "{$user} is not allowed to provide accession number directly") -class UserCanNotUpdateSubmit(submission: ExtendedSubmission) : InvalidPermissionsException( - "{${submission.user.email}} is not allowed to update submission ${submission.accNo}") +class UserCanNotUpdateSubmit(accNo: String, user: String) : InvalidPermissionsException( + "{$user} is not allowed to update submission $accNo") -class UserCanNotSubmitProjectsException(user: User) : InvalidPermissionsException( - "The user ${user.email} is not allowed to submit projects") +class UserCanNotSubmitProjectsException(user: String) : InvalidPermissionsException( + "The user $user is not allowed to submit projects") diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesCopier.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesCopier.kt deleted file mode 100644 index 36ffe65c1c..0000000000 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesCopier.kt +++ /dev/null @@ -1,32 +0,0 @@ -package ac.uk.ebi.biostd.submission.handlers - -import ebi.ac.uk.io.sources.FilesSource -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.File -import ebi.ac.uk.model.extensions.allFiles -import ebi.ac.uk.model.extensions.allReferencedFiles -import ebi.ac.uk.paths.SubmissionFolderResolver -import org.apache.commons.io.FileUtils - -class FilesCopier(private val folderResolver: SubmissionFolderResolver) { - fun copy(submission: ExtendedSubmission, filesSource: FilesSource) { - copySubmissionFiles(submission, filesSource) - copyReferencedFiles(submission, filesSource) - } - - private fun copySubmissionFiles(submission: ExtendedSubmission, filesSource: FilesSource) = - copy(submission.allFiles(), submission, filesSource) - - private fun copyReferencedFiles(submission: ExtendedSubmission, filesSource: FilesSource) = - copy(submission.allReferencedFiles(), submission, filesSource) - - private fun copy(files: List, submission: ExtendedSubmission, filesSource: FilesSource) { - files.forEach { targetFile -> - val submissionFile = folderResolver.getSubFilePath(submission.relPath, targetFile.path).toFile() - - // TODO Refactor the size calculation out in order to avoid mixing concerns - targetFile.size = filesSource.size(targetFile.path) - FileUtils.copyFile(filesSource.getFile(targetFile.path), submissionFile) - } - } -} diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesHandler.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesHandler.kt deleted file mode 100644 index a8d9f808ec..0000000000 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesHandler.kt +++ /dev/null @@ -1,20 +0,0 @@ -package ac.uk.ebi.biostd.submission.handlers - -import ebi.ac.uk.io.sources.FilesSource -import ebi.ac.uk.model.ExtendedSubmission - -class FilesHandler( - private val filesValidator: FilesValidator, - private val filesCopier: FilesCopier, - private val outputFilesGenerator: OutputFilesGenerator -) { - /** - * In charge of generate submission json/tsv/xml representation files and validate all submission specified files - * are provided or exists in user repository or in the list of provided files. - */ - fun processFiles(submission: ExtendedSubmission, fileSource: FilesSource) { - filesValidator.validate(submission, fileSource) - filesCopier.copy(submission, fileSource) - outputFilesGenerator.generate(submission) - } -} diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesValidator.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesValidator.kt deleted file mode 100644 index b9991c1a0a..0000000000 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesValidator.kt +++ /dev/null @@ -1,19 +0,0 @@ -package ac.uk.ebi.biostd.submission.handlers - -import ac.uk.ebi.biostd.submission.exceptions.InvalidFilesException -import ebi.ac.uk.io.sources.FilesSource -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.extensions.allFiles -import ebi.ac.uk.util.collections.ifNotEmpty - -class FilesValidator { - fun validate(submission: ExtendedSubmission, filesSource: FilesSource) { - validateFiles(submission, filesSource) - } - - private fun validateFiles(submission: ExtendedSubmission, filesSource: FilesSource) { - submission.allFiles() - .filter { file -> filesSource.exists(file.path).not() } - .ifNotEmpty { throw InvalidFilesException(it) } - } -} diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/OutputFilesGenerator.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/OutputFilesGenerator.kt deleted file mode 100644 index 4602385995..0000000000 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/handlers/OutputFilesGenerator.kt +++ /dev/null @@ -1,44 +0,0 @@ -package ac.uk.ebi.biostd.submission.handlers - -import ac.uk.ebi.biostd.integration.SerializationService -import ac.uk.ebi.biostd.integration.SubFormat -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.FilesTable -import ebi.ac.uk.model.extensions.allFileListSections -import ebi.ac.uk.model.extensions.fileListAttr -import ebi.ac.uk.paths.SubmissionFolderResolver -import org.apache.commons.io.FileUtils - -class OutputFilesGenerator( - private val folderResolver: SubmissionFolderResolver, - private val serializationService: SerializationService -) { - fun generate(submission: ExtendedSubmission) { - generateFileList(submission) - generateSubmissionFiles(submission) - } - - private fun generateSubmissionFiles(submission: ExtendedSubmission) = - generateOutputFiles(submission.asSubmission(), submission, submission.accNo) - - private fun generateFileList(submission: ExtendedSubmission) = - submission.allFileListSections().forEach { - val fileListName = it.fileList!!.name.substringBeforeLast(".") - val filesTable = FilesTable(it.fileList!!.referencedFiles.toList()) - - it.fileListAttr = fileListName - it.fileList!!.name = fileListName - generateOutputFiles(filesTable, submission, fileListName) - } - - private fun generateOutputFiles(element: T, submission: ExtendedSubmission, outputFileName: String) { - val json = serializationService.serializeElement(element, SubFormat.JSON_PRETTY) - val xml = serializationService.serializeElement(element, SubFormat.XML) - val tsv = serializationService.serializeElement(element, SubFormat.TSV) - val submissionPath = folderResolver.getSubmissionFolder(submission) - - FileUtils.writeStringToFile(submissionPath.resolve("$outputFileName.json").toFile(), json, Charsets.UTF_8) - FileUtils.writeStringToFile(submissionPath.resolve("$outputFileName.xml").toFile(), xml, Charsets.UTF_8) - FileUtils.writeStringToFile(submissionPath.resolve("$outputFileName.pagetab.tsv").toFile(), tsv, Charsets.UTF_8) - } -} diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/model/SubmissionRequest.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/model/SubmissionRequest.kt index aae8991d18..312e1425c6 100644 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/model/SubmissionRequest.kt +++ b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/model/SubmissionRequest.kt @@ -9,5 +9,5 @@ data class SubmissionRequest( val submission: Submission, val user: SecurityUser, val files: FilesSource, - val method: SubmissionMethod? + val method: SubmissionMethod ) diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/AccNoService.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/AccNoService.kt index eaeb4be497..6c57e7a1ac 100644 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/AccNoService.kt +++ b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/AccNoService.kt @@ -1,15 +1,12 @@ package ac.uk.ebi.biostd.submission.service +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.submission.exceptions.ProvideAccessNumber +import ac.uk.ebi.biostd.submission.exceptions.UserCanNotSubmitProjectsException import ac.uk.ebi.biostd.submission.exceptions.UserCanNotUpdateSubmit import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil -import arrow.core.Option -import arrow.core.getOrElse import ebi.ac.uk.base.lastDigits import ebi.ac.uk.model.AccNumber -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.extensions.attachTo -import ebi.ac.uk.persistence.PersistenceContext import ebi.ac.uk.security.integration.components.IUserPrivilegesService const val DEFAULT_PATTERN = "!{S-BSST}" @@ -18,32 +15,34 @@ const val PATH_DIGITS = 3 class AccNoService( private val context: PersistenceContext, private val patternUtil: AccNoPatternUtil, - private val userPrivilegesService: IUserPrivilegesService + private val privilegesService: IUserPrivilegesService ) { - fun getAccNo(submission: ExtendedSubmission): AccNumber = when { - submission.accNo.isNotEmpty() && - context.isNew(submission.accNo) && - userPrivilegesService.canProvideAccNo(submission.user.email).not() -> - throw ProvideAccessNumber(submission.user) - userPrivilegesService.canResubmit( - submission.user.email, submission.user, submission.attachTo, submission.accessTags).not() -> - throw UserCanNotUpdateSubmit(submission) - else -> - calculateAccNo(submission) - } + @Suppress("ThrowsCount") + fun getAccNo(request: AccNoServiceRequest): AccNumber { + val (submitter, accNo, project, projectPattern) = request - private fun calculateAccNo(submission: ExtendedSubmission): AccNumber { - return when { - submission.accNo.isEmpty() -> - calculateAccNo(getPatternOrDefault(context.getParentAccPattern(submission))) - patternUtil.isPattern(submission.accNo) -> - calculateAccNo(patternUtil.getPattern(submission.accNo)) - else -> patternUtil.toAccNumber(submission.accNo) + when { + accNo == null || context.isNew(accNo) -> { + if (accNo != null && privilegesService.canProvideAccNo(submitter).not()) + throw ProvideAccessNumber(submitter) + if (project != null && privilegesService.canSubmitToProject(submitter, project).not()) + throw UserCanNotSubmitProjectsException(submitter) + + return accNo?.let { AccNumber(accNo) } ?: calculateAccNo(getPatternOrDefault(projectPattern)) + } + else -> { + if (project != null && privilegesService.canSubmitToProject(submitter, project).not()) + throw UserCanNotSubmitProjectsException(submitter) + + if (privilegesService.canResubmit(submitter, accNo).not()) + throw UserCanNotUpdateSubmit(accNo, submitter) + + return AccNumber(accNo) + } } } - private fun calculateAccNo(prefix: String) = - AccNumber(prefix, context.getSequenceNextValue(prefix)) + private fun calculateAccNo(pattern: String) = AccNumber(pattern, context.getSequenceNextValue(pattern)) @Suppress("MagicNumber") internal fun getRelPath(accNo: AccNumber): String { @@ -51,13 +50,24 @@ class AccNoService( val value = accNo.numericValue return when { - accNo.numericValue < 99 -> + value == null -> + prefix.removePrefix("/") + value < 99 -> "$prefix/${prefix}0-99/$prefix$value".removePrefix("/") else -> "$prefix/${prefix}xxx${value.lastDigits(PATH_DIGITS)}/$prefix$value".removePrefix("/") } } - private fun getPatternOrDefault(pattern: Option) = - pattern.map { patternUtil.getPattern(it) }.getOrElse { patternUtil.getPattern(DEFAULT_PATTERN) } + private fun getPatternOrDefault(parentPattern: String?) = when (parentPattern) { + null -> patternUtil.getPattern(DEFAULT_PATTERN) + else -> patternUtil.getPattern(parentPattern) + } } + +data class AccNoServiceRequest( + val submitter: String, + val accNo: String? = null, + val project: String? = null, + val projectPattern: String? = null +) diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ParentInfoService.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ParentInfoService.kt new file mode 100644 index 0000000000..30688abb27 --- /dev/null +++ b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ParentInfoService.kt @@ -0,0 +1,19 @@ +package ac.uk.ebi.biostd.submission.service + +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext +import java.time.OffsetDateTime + +class ParentInfoService(private val ctx: PersistenceContext) { + fun getParentInfo(parentAccNo: String?): ParentInfo = when (parentAccNo) { + null -> ParentInfo(emptyList(), null, null) + else -> { + require(ctx.existByAccNo(parentAccNo)) { "Could not find a project register with accNo $parentAccNo" } + ParentInfo( + ctx.getAccessTags(parentAccNo).filterNot { it == "Public" }, + ctx.getReleaseTime(parentAccNo), + ctx.getParentAccPattern(parentAccNo).orNull()) + } + } +} + +data class ParentInfo(val accessTags: List, val releaseTime: OffsetDateTime?, val parentTemplate: String?) diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ProjectInfoService.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ProjectInfoService.kt new file mode 100644 index 0000000000..a27b1991aa --- /dev/null +++ b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ProjectInfoService.kt @@ -0,0 +1,41 @@ +package ac.uk.ebi.biostd.submission.service + +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext +import ac.uk.ebi.biostd.submission.exceptions.ProjectAlreadyExistingException +import ac.uk.ebi.biostd.submission.exceptions.ProjectInvalidAccNoPatternException +import ac.uk.ebi.biostd.submission.exceptions.UserCanNotSubmitProjectsException +import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil +import ebi.ac.uk.security.integration.components.IUserPrivilegesService + +internal const val ACC_NO_TEMPLATE_REQUIRED = "The project accession number pattern is required" +internal const val ACC_NO_TEMPLATE_INVALID = "The given template is invalid. Expected pattern is !{TEMPLATE}" + +class ProjectInfoService( + private val context: PersistenceContext, + private val accNoUtil: AccNoPatternUtil, + private val privilegesService: IUserPrivilegesService +) { + @Suppress("ThrowsCount") + fun process(request: ProjectRequest): ProjectResponse? { + if (request.subType != "Project") return null + + val submitter = request.submitter + val template = request.accNoTemplate + val accNo = request.accNo + + require(privilegesService.canSubmitProjects(submitter)) { throw UserCanNotSubmitProjectsException(submitter) } + require(template != null) { throw ProjectInvalidAccNoPatternException(ACC_NO_TEMPLATE_REQUIRED) } + require(accNoUtil.isPattern(template)) { throw ProjectInvalidAccNoPatternException(ACC_NO_TEMPLATE_INVALID) } + require(context.isNew(accNo).not() || context.accessTagExists(accNo).not()) { + throw ProjectAlreadyExistingException(accNo) + } + + context.createAccNoPatternSequence(accNoUtil.getPattern(template)) + context.saveAccessTag(accNo) + + return ProjectResponse(request.accNo) + } +} + +data class ProjectRequest(val submitter: String, val subType: String, val accNoTemplate: String?, val accNo: String) +data class ProjectResponse(val accessTag: String) diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ProjectValidationService.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ProjectValidationService.kt deleted file mode 100644 index 8d86d45c4c..0000000000 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/ProjectValidationService.kt +++ /dev/null @@ -1,50 +0,0 @@ -package ac.uk.ebi.biostd.submission.service - -import ac.uk.ebi.biostd.submission.exceptions.ProjectAccessTagAlreadyExistingException -import ac.uk.ebi.biostd.submission.exceptions.ProjectAlreadyExistingException -import ac.uk.ebi.biostd.submission.exceptions.ProjectInvalidAccNoPatternException -import ac.uk.ebi.biostd.submission.exceptions.UserCanNotSubmitProjectsException -import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil -import ebi.ac.uk.base.isNotBlank -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.extensions.accNoTemplate -import ebi.ac.uk.persistence.PersistenceContext -import ebi.ac.uk.security.integration.components.IUserPrivilegesService - -internal const val ACC_NO_TEMPLATE_REQUIRED = "The project accession number pattern is required" -internal const val ACC_NO_TEMPLATE_INVALID = "The given template is invalid. Expected pattern is !{TEMPLATE}" - -class ProjectValidationService( - private val persistenceContext: PersistenceContext, - private val accNoPatternUtil: AccNoPatternUtil, - private val userPrivilegesService: IUserPrivilegesService -) { - fun validate(project: ExtendedSubmission) { - validatePrivileges(project) - validateAccNoTemplate(project) - validateProject(project) - } - - private fun validatePrivileges(project: ExtendedSubmission) { - require(userPrivilegesService.canSubmitProjects(project.user.email)) { - throw UserCanNotSubmitProjectsException(project.user) - } - } - - private fun validateAccNoTemplate(project: ExtendedSubmission) { - require(project.accNoTemplate.isNotBlank()) { - throw ProjectInvalidAccNoPatternException(ACC_NO_TEMPLATE_REQUIRED) - } - - require(accNoPatternUtil.isPattern(project.accNoTemplate!!)) { - throw ProjectInvalidAccNoPatternException(ACC_NO_TEMPLATE_INVALID) - } - } - - private fun validateProject(project: ExtendedSubmission) { - require(persistenceContext.isNew(project.accNo)) { throw ProjectAlreadyExistingException(project.accNo) } - require(persistenceContext.accessTagExists(project.accNo).not()) { - throw ProjectAccessTagAlreadyExistingException(project.accNo) - } - } -} diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/TimesService.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/TimesService.kt index 15dd93715a..c30f7a6d6b 100644 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/TimesService.kt +++ b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/service/TimesService.kt @@ -1,9 +1,7 @@ package ac.uk.ebi.biostd.submission.service +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.submission.exceptions.InvalidDateFormatException -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.extensions.releaseDate -import ebi.ac.uk.persistence.PersistenceContext import java.time.Instant import java.time.LocalDate import java.time.OffsetDateTime @@ -14,10 +12,10 @@ import java.time.ZoneOffset * Calculates the submission release date based on current state of the submission in the system. Calculation rules. */ class TimesService(private val context: PersistenceContext) { - internal fun getTimes(submission: ExtendedSubmission): Times { + internal fun getTimes(request: TimesRequest): Times { val now = OffsetDateTime.now() - val creationTime = context.getSubmission(submission.accNo)?.creationTime ?: now - val releaseTime = submission.releaseDate?.let { parseDate(it) } + val creationTime = context.findCreationTime(request.accNo) ?: now + val releaseTime = request.releaseDate?.let { parseDate(it) } return Times(creationTime, now, releaseTime) } @@ -32,3 +30,9 @@ data class Times( val modificationTime: OffsetDateTime, val releaseTime: OffsetDateTime? ) + +data class TimesRequest( + val accNo: String, + val releaseDate: String? = null, + val parentReleaseTime: OffsetDateTime? = null +) diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/submitter/ProjectSubmitter.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/submitter/ProjectSubmitter.kt deleted file mode 100644 index 3fc679f690..0000000000 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/submitter/ProjectSubmitter.kt +++ /dev/null @@ -1,66 +0,0 @@ -package ac.uk.ebi.biostd.submission.submitter - -import ac.uk.ebi.biostd.submission.exceptions.InvalidDateFormatException -import ac.uk.ebi.biostd.submission.exceptions.InvalidSubmissionException -import ac.uk.ebi.biostd.submission.service.ProjectValidationService -import ac.uk.ebi.biostd.submission.service.TimesService -import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil -import ebi.ac.uk.base.orFalse -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.Submission -import ebi.ac.uk.model.constants.ProcessingStatus.PROCESSED -import ebi.ac.uk.model.constants.SubFields -import ebi.ac.uk.model.extensions.accNoTemplate -import ebi.ac.uk.model.extensions.addAccessTag -import ebi.ac.uk.model.extensions.releaseDate -import ebi.ac.uk.persistence.PersistenceContext -import ebi.ac.uk.util.date.isBeforeOrEqual -import org.springframework.transaction.annotation.Isolation -import org.springframework.transaction.annotation.Transactional -import java.time.Instant -import java.time.LocalDate -import java.time.OffsetDateTime -import java.time.ZoneId -import java.time.ZoneOffset - -open class ProjectSubmitter( - private val timesService: TimesService, - private val accNoPatternUtil: AccNoPatternUtil, - private val persistenceContext: PersistenceContext, - private val projectValidationService: ProjectValidationService -) { - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - open fun submit(project: ExtendedSubmission): Submission = - runCatching { process(project) }.fold( - { persist(project) }, - { throw InvalidSubmissionException("Submission validation errors", listOf(it)) }) - - private fun process(project: ExtendedSubmission): ExtendedSubmission { - projectValidationService.validate(project) - - val releaseTime = project.releaseDate?.let { parseDate(it) } - if (releaseTime?.isBeforeOrEqual(OffsetDateTime.now()).orFalse()) { - project.released = true - project.addAccessTag(SubFields.PUBLIC_ACCESS_TAG.value) - } - - project.addAccessTag(project.accNo) - project.releaseTime = releaseTime - - return project - } - - private fun persist(project: ExtendedSubmission): Submission { - val sequencePrefix = accNoPatternUtil.getPattern(project.accNoTemplate!!) - persistenceContext.createAccNoPatternSequence(sequencePrefix) - persistenceContext.saveAccessTag(project.accNo) - project.processingStatus = PROCESSED - - return persistenceContext.saveSubmission(project) - } - - private fun parseDate(date: String): OffsetDateTime = - runCatching { LocalDate.parse(date) } - .recoverCatching { Instant.parse(date).atZone(ZoneId.systemDefault()).toLocalDate() } - .fold({ it.atStartOfDay().atOffset(ZoneOffset.UTC) }, { throw InvalidDateFormatException(date) }) -} diff --git a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/submitter/SubmissionSubmitter.kt b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/submitter/SubmissionSubmitter.kt index 8e4dfbeb50..24eddde651 100644 --- a/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/submitter/SubmissionSubmitter.kt +++ b/submission/submitter/src/main/kotlin/ac/uk/ebi/biostd/submission/submitter/SubmissionSubmitter.kt @@ -1,19 +1,35 @@ package ac.uk.ebi.biostd.submission.submitter +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.submission.exceptions.InvalidSubmissionException -import ac.uk.ebi.biostd.submission.handlers.FilesHandler import ac.uk.ebi.biostd.submission.model.SubmissionRequest import ac.uk.ebi.biostd.submission.service.AccNoService +import ac.uk.ebi.biostd.submission.service.AccNoServiceRequest +import ac.uk.ebi.biostd.submission.service.ParentInfoService +import ac.uk.ebi.biostd.submission.service.ProjectRequest +import ac.uk.ebi.biostd.submission.service.ProjectResponse +import ac.uk.ebi.biostd.submission.service.ProjectInfoService +import ac.uk.ebi.biostd.submission.service.TimesRequest import ac.uk.ebi.biostd.submission.service.TimesService import ebi.ac.uk.base.orFalse +import ebi.ac.uk.extended.mapping.serialization.from.toExtAttribute +import ebi.ac.uk.extended.mapping.serialization.from.toExtSection +import ebi.ac.uk.extended.mapping.serialization.to.toSimpleSubmission +import ebi.ac.uk.extended.model.ExtAccessTag +import ebi.ac.uk.extended.model.ExtSubmission +import ebi.ac.uk.extended.model.ExtTag import ebi.ac.uk.io.sources.FilesSource -import ebi.ac.uk.model.ExtendedSubmission import ebi.ac.uk.model.Submission +import ebi.ac.uk.model.SubmissionMethod +import ebi.ac.uk.model.User import ebi.ac.uk.model.constants.ProcessingStatus import ebi.ac.uk.model.constants.SubFields -import ebi.ac.uk.model.extensions.addAccessTag +import ebi.ac.uk.model.constants.SubFields.PUBLIC_ACCESS_TAG +import ebi.ac.uk.model.extensions.accNoTemplate +import ebi.ac.uk.model.extensions.attachTo import ebi.ac.uk.model.extensions.releaseDate -import ebi.ac.uk.persistence.PersistenceContext +import ebi.ac.uk.model.extensions.rootPath +import ebi.ac.uk.model.extensions.title import ebi.ac.uk.util.date.isBeforeOrEqual import org.springframework.transaction.annotation.Isolation import org.springframework.transaction.annotation.Transactional @@ -21,57 +37,86 @@ import java.time.OffsetDateTime import java.util.UUID open class SubmissionSubmitter( - private val filesHandler: FilesHandler, private val timesService: TimesService, private val accNoService: AccNoService, - private val persistenceContext: PersistenceContext + private val parentInfoService: ParentInfoService, + private val projectInfoService: ProjectInfoService, + private val context: PersistenceContext ) { @Transactional(isolation = Isolation.READ_UNCOMMITTED) open fun submit(request: SubmissionRequest): Submission { - val submission = ExtendedSubmission(request.submission, request.user.asUser()) - val processingErrors = process(submission, request.files) + val user = request.user.asUser() + val extSubmission = process(request.submission, request.user.asUser(), request.files, request.method) + return context.saveSubmission(extSubmission, user.email, user.id).toSimpleSubmission() + } - if (processingErrors.isEmpty()) { - persistenceContext.deleteSubmissionDrafts(submission) - submission.processingStatus = ProcessingStatus.PROCESSED - submission.method = request.method - return persistenceContext.saveSubmission(submission) + @Suppress("TooGenericExceptionCaught") + private fun process( + submission: Submission, + user: User, + source: FilesSource, + method: SubmissionMethod + ): ExtSubmission { + try { + return processSubmission(submission, user, source, method) + } catch (e: RuntimeException) { + throw InvalidSubmissionException("Submission validation errors", listOf(e)) } + } + + private fun processSubmission(submission: Submission, user: User, source: FilesSource, method: SubmissionMethod): + ExtSubmission { + val (parentTags, parentReleaseTime, parentPattern) = parentInfoService.getParentInfo(submission.attachTo) + val (createTime, modTime, releaseTime) = getTimes(submission, parentReleaseTime) + val released = releaseTime?.isBeforeOrEqual(OffsetDateTime.now()).orFalse() + val accNo = getAccNumber(submission, user, parentPattern) + val accNoString = accNo.toString() + val projectInfo = getProjectInfo(user, submission, accNoString) + val secretKey = getSecret(accNoString) + val nextVersion = context.getNextVersion(accNoString) + val relPath = accNoService.getRelPath(accNo) + val tags = getTags(released, parentTags, projectInfo) - throw InvalidSubmissionException("Submission validation errors", processingErrors) + return ExtSubmission( + accNo = accNoString, + version = nextVersion, + method = method, + title = submission.title, + relPath = relPath, + rootPath = submission.rootPath, + released = released, + secretKey = secretKey, + status = ProcessingStatus.PROCESSED, + releaseTime = releaseTime, + modificationTime = modTime, + creationTime = createTime, + tags = submission.tags.map { ExtTag(it.first, it.second) }, + accessTags = tags.map { ExtAccessTag(it) }, + section = submission.section.toExtSection(source), + attributes = getAttributes(submission) + ) } - private fun process(submission: ExtendedSubmission, source: FilesSource) = - listOf( - runCatching { processSubmission(submission) }, - runCatching { filesHandler.processFiles(submission, source) } - ).mapNotNull { it.exceptionOrNull() } + private fun getTags(released: Boolean, parentTags: List, project: ProjectResponse?): MutableList { + val tags = parentTags.toMutableList() + if (released) tags.add(PUBLIC_ACCESS_TAG.value) + if (project != null) tags.add(project.accessTag) + return tags + } - private fun processSubmission(submission: ExtendedSubmission): ExtendedSubmission { - val parentTags = persistenceContext.getParentAccessTags(submission).filterNot { it == "Public" } - val (creationTime, modificationTime, releaseTime) = timesService.getTimes(submission) + private fun getProjectInfo(user: User, submission: Submission, accNo: String) = + projectInfoService.process(ProjectRequest(user.email, submission.section.type, submission.accNoTemplate, accNo)) - submission.accessTags = parentTags.toMutableList() - if (releaseTime?.isBeforeOrEqual(OffsetDateTime.now()).orFalse()) { - submission.released = true - submission.addAccessTag(SubFields.PUBLIC_ACCESS_TAG.value) - } + private fun getAttributes(submission: Submission) = submission.attributes + .filter { it.name != SubFields.RELEASE_DATE.value } + .map { it.toExtAttribute() } - val accNo = accNoService.getAccNo(submission) - val accString = accNo.toString() - val relPath = accNoService.getRelPath(accNo) - val secretKey = - if (persistenceContext.isNew(accString)) UUID.randomUUID().toString() - else persistenceContext.getSecret(accString) + private fun getAccNumber(sub: Submission, user: User, parentPattern: String?) = + accNoService.getAccNo(AccNoServiceRequest(user.email, sub.accNo.ifBlank { null }, sub.attachTo, parentPattern)) - submission.accNo = accString - submission.relPath = relPath - submission.releaseDate = null - submission.creationTime = creationTime - submission.modificationTime = modificationTime - submission.releaseTime = releaseTime - submission.secretKey = secretKey + private fun getTimes(sub: Submission, parentReleaseTime: OffsetDateTime?) = + timesService.getTimes(TimesRequest(sub.accNo, sub.releaseDate, parentReleaseTime)) - return submission - } + private fun getSecret(accString: String) = + if (context.isNew(accString)) UUID.randomUUID().toString() else context.getSecret(accString) } diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesHandlerTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesHandlerTest.kt deleted file mode 100644 index 51dfbe19b3..0000000000 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/handlers/FilesHandlerTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -package ac.uk.ebi.biostd.submission.handlers - -import ac.uk.ebi.biostd.submission.test.ACC_NO -import ac.uk.ebi.biostd.submission.test.USER_SECRET_KEY -import ac.uk.ebi.biostd.submission.test.createBasicExtendedSubmission -import ebi.ac.uk.io.sources.FilesSource -import ebi.ac.uk.model.ExtendedSubmission -import io.github.glytching.junit.extension.folder.TemporaryFolder -import io.github.glytching.junit.extension.folder.TemporaryFolderExtension -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.verify -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(TemporaryFolderExtension::class, MockKExtension::class) -class FilesHandlerTest( - private val temporaryFolder: TemporaryFolder, - @MockK private val mockFilesCopier: FilesCopier, - @MockK private val mockFilesValidator: FilesValidator, - @MockK private val mockOutputFilesGenerator: OutputFilesGenerator -) { - private lateinit var submission: ExtendedSubmission - private lateinit var testInstance: FilesHandler - - @BeforeAll - fun beforeAll() { - temporaryFolder.createDirectory(ACC_NO) - temporaryFolder.createDirectory(USER_SECRET_KEY) - } - - @BeforeEach - fun beforeEach() { - submission = createBasicExtendedSubmission() - testInstance = FilesHandler(mockFilesValidator, mockFilesCopier, mockOutputFilesGenerator) - - initMocks() - } - - // TODO add unit tests for the individual processors - @Test - fun `process submission files`(@MockK userSource: FilesSource) { - testInstance.processFiles(submission, userSource) - - verify(exactly = 1) { mockFilesCopier.copy(submission, userSource) } - verify(exactly = 1) { mockFilesValidator.validate(submission, userSource) } - verify(exactly = 1) { mockOutputFilesGenerator.generate(submission) } - } - - private fun initMocks() { - every { mockFilesCopier.copy(submission, any()) } answers { nothing } - every { mockFilesValidator.validate(submission, any()) } answers { nothing } - every { mockOutputFilesGenerator.generate(submission) } answers { nothing } - } -} diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/handlers/OutputFilesGeneratorTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/handlers/OutputFilesGeneratorTest.kt deleted file mode 100644 index 1a9835d8e9..0000000000 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/handlers/OutputFilesGeneratorTest.kt +++ /dev/null @@ -1,43 +0,0 @@ -package ac.uk.ebi.biostd.submission.handlers - -import ac.uk.ebi.biostd.integration.SerializationService -import ac.uk.ebi.biostd.integration.SubFormat -import ac.uk.ebi.biostd.submission.test.createBasicExtendedSubmission -import ebi.ac.uk.paths.SubmissionFolderResolver -import io.github.glytching.junit.extension.folder.TemporaryFolder -import io.github.glytching.junit.extension.folder.TemporaryFolderExtension -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import java.nio.file.Paths - -@ExtendWith(TemporaryFolderExtension::class, MockKExtension::class) -class OutputFilesGeneratorTest( - private val temporaryFolder: TemporaryFolder, - @MockK private val mockFolderResolver: SubmissionFolderResolver, - @MockK private val mockSerializationService: SerializationService -) { - private val submission = createBasicExtendedSubmission() - private val testInstance = OutputFilesGenerator(mockFolderResolver, mockSerializationService) - - @BeforeEach - fun beforeEach() { - every { mockSerializationService.serializeElement(submission.asSubmission(), SubFormat.XML) } returns "" - every { mockSerializationService.serializeElement(submission.asSubmission(), SubFormat.TSV) } returns "" - every { mockSerializationService.serializeElement(submission.asSubmission(), SubFormat.JSON_PRETTY) } returns "" - every { mockFolderResolver.getSubmissionFolder(submission) } returns temporaryFolder.root.toPath() - } - - @Test - fun `submission output files`() { - testInstance.generate(submission) - - assertThat(Paths.get("${temporaryFolder.root.absolutePath}/ABC456.xml")).exists() - assertThat(Paths.get("${temporaryFolder.root.absolutePath}/ABC456.json")).exists() - assertThat(Paths.get("${temporaryFolder.root.absolutePath}/ABC456.pagetab.tsv")).exists() - } -} diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/AccNoServiceTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/AccNoServiceTest.kt index 30b6b0fc40..ac51405434 100644 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/AccNoServiceTest.kt +++ b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/AccNoServiceTest.kt @@ -1,91 +1,151 @@ package ac.uk.ebi.biostd.submission.service -import ac.uk.ebi.biostd.submission.exceptions.InvalidPermissionsException +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext +import ac.uk.ebi.biostd.submission.exceptions.ProvideAccessNumber +import ac.uk.ebi.biostd.submission.exceptions.UserCanNotSubmitProjectsException import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil -import arrow.core.Option -import ebi.ac.uk.base.EMPTY import ebi.ac.uk.model.AccNumber -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.User -import ebi.ac.uk.persistence.PersistenceContext import ebi.ac.uk.security.integration.components.IUserPrivilegesService import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource +private const val SUB_ACC_NO = "AAB12" +private const val SUBMITTER = "submiter@email.com" +private const val PROJECT = "CC123" +private const val PROJECT_PATTERN = "!{ABC-}" + @ExtendWith(MockKExtension::class) class AccNoServiceTest( - @MockK private val user: User, @MockK private val accNoPatternUtil: AccNoPatternUtil, - @MockK private val persistenceContext: PersistenceContext, - @MockK private val userPrivilegesService: IUserPrivilegesService + @MockK private val context: PersistenceContext, + @MockK private val privilegesService: IUserPrivilegesService ) { - private val submission = ExtendedSubmission("AAB12", user) - private val testInstance = AccNoService(persistenceContext, accNoPatternUtil, userPrivilegesService) - - @BeforeEach - fun init() { - every { user.email } returns "test@mail.com" - every { persistenceContext.isNew("") } returns true - every { persistenceContext.getParentAccPattern(submission) } returns Option.empty() - every { accNoPatternUtil.isPattern(EMPTY) } returns false - every { userPrivilegesService.canProvideAccNo("test@mail.com") } returns true - every { userPrivilegesService.canResubmit("test@mail.com", user, null, emptyList()) } returns true - } + private val testInstance = AccNoService(context, accNoPatternUtil, privilegesService) @ParameterizedTest(name = "prefix is {0} and numeric value is {1}") @CsvSource( "AA, 88, AA/AA0-99/AA88", "AA, 200, AA/AAxxx200/AA200" ) - fun submitUserCanSubmit(prefix: String, value: Long, expected: String) { + fun getRelPath(prefix: String, value: Long, expected: String) { assertThat(testInstance.getRelPath(AccNumber(prefix, value))).isEqualTo(expected) } - @Test - fun `no accession number, no parent accession`() { - val submission = ExtendedSubmission(EMPTY, user) + @Nested + inner class WhenIsNew { - every { accNoPatternUtil.getPattern(DEFAULT_PATTERN) } returns "S-BSST" - every { persistenceContext.getParentAccPattern(submission) } returns Option.empty() - every { persistenceContext.getSequenceNextValue("S-BSST") } returns 1L + @BeforeEach + fun beforeEach() { + every { context.isNew(SUB_ACC_NO) } returns true + } - val accNo = testInstance.getAccNo(submission).toString() - assertThat(accNo).isEqualTo("S-BSST1") - } + @Test + fun whenUserCanNoProvideAccession() { + every { privilegesService.canProvideAccNo(SUBMITTER) } returns false - @Test - fun `no accession number but parent accession`() { - val submission = ExtendedSubmission(EMPTY, user) + assertThrows { + testInstance.getAccNo(AccNoServiceRequest(SUBMITTER, SUB_ACC_NO)) + } + } - every { accNoPatternUtil.getPattern("!{P-ARENT,}") } returns "P-ARENT" - every { persistenceContext.getParentAccPattern(submission) } returns Option.just("!{P-ARENT,}") - every { persistenceContext.getSequenceNextValue("P-ARENT") } returns 1 + @Test + fun whenUserCanNotSubmitToProject() { + every { privilegesService.canSubmitToProject(SUBMITTER, PROJECT) } returns false - val accNo = testInstance.getAccNo(submission).toString() - assertThat(accNo).isEqualTo("P-ARENT1") - } + assertThrows { + testInstance.getAccNo(AccNoServiceRequest(submitter = SUBMITTER, project = PROJECT)) + } + } + + @Nested + inner class WhenAccNo { + + @Test + fun whenNoProject() { + every { privilegesService.canProvideAccNo(SUBMITTER) } returns true + + assertThat(testInstance.getAccNo(AccNoServiceRequest(submitter = SUBMITTER, accNo = SUB_ACC_NO))) + .isEqualTo(AccNumber(SUB_ACC_NO)) + } + + @Test + fun whenProject() { + every { privilegesService.canProvideAccNo(SUBMITTER) } returns true + every { privilegesService.canSubmitToProject(SUBMITTER, PROJECT) } returns true + + assertThat(testInstance.getAccNo( + AccNoServiceRequest(submitter = SUBMITTER, accNo = SUB_ACC_NO, project = PROJECT))) + .isEqualTo(AccNumber(SUB_ACC_NO)) + } + } - @Test - fun `submission is new and user is not allowed provide accession number`() { - every { persistenceContext.isNew("AAB12") } returns true - every { userPrivilegesService.canProvideAccNo("test@mail.com") } returns false + @Nested + inner class WhenNoAccNo { + @Test + fun whenParent() { + every { privilegesService.canSubmitToProject(SUBMITTER, PROJECT) } returns true - assertThrows { testInstance.getAccNo(submission) } + val projectSequence = "abc-" + every { accNoPatternUtil.getPattern(PROJECT_PATTERN) } returns projectSequence + every { context.getSequenceNextValue(projectSequence) } returns 10 + + assertThat(testInstance.getAccNo(AccNoServiceRequest( + submitter = SUBMITTER, + project = PROJECT, + projectPattern = PROJECT_PATTERN))) + .isEqualTo(AccNumber("abc-", 10)) + } + + @Test + fun whenNoParent() { + every { privilegesService.canProvideAccNo(SUBMITTER) } returns true + every { privilegesService.canSubmitToProject(SUBMITTER, PROJECT) } returns true + + val defaultSequence = "default-" + every { accNoPatternUtil.getPattern(DEFAULT_PATTERN) } returns defaultSequence + every { context.getSequenceNextValue(defaultSequence) } returns 99 + + assertThat(testInstance.getAccNo(AccNoServiceRequest( + submitter = SUBMITTER, + project = PROJECT))) + .isEqualTo(AccNumber("default-", 99)) + } + } } - @Test - fun `submission is not new and user is not allowed to update submission`() { - every { persistenceContext.isNew("AAB12") } returns false - every { userPrivilegesService.canResubmit("test@mail.com", user, null, emptyList()) } returns false + @Nested + inner class WhenIsNotNew { + + @BeforeEach + fun beforeEach() { + every { context.isNew(SUB_ACC_NO) } returns false + } + + @Test + fun whenUserCanNotSubmitToProject() { + every { privilegesService.canSubmitToProject(SUBMITTER, PROJECT) } returns false + + assertThrows { + testInstance.getAccNo(AccNoServiceRequest(submitter = SUBMITTER, accNo = SUB_ACC_NO, project = PROJECT)) + } + } + + @Test + fun whenUserCanNotReSubmit() { + every { privilegesService.canSubmitToProject(SUBMITTER, PROJECT) } returns false - assertThrows { testInstance.getAccNo(submission) } + assertThrows { + testInstance.getAccNo(AccNoServiceRequest(submitter = SUBMITTER, accNo = SUB_ACC_NO, project = PROJECT)) + } + } } } diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/ProjectValidationServiceTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/ProjectValidationServiceTest.kt deleted file mode 100644 index 510b86ed12..0000000000 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/ProjectValidationServiceTest.kt +++ /dev/null @@ -1,131 +0,0 @@ -package ac.uk.ebi.biostd.submission.service - -import ac.uk.ebi.biostd.submission.exceptions.ProjectAccessTagAlreadyExistingException -import ac.uk.ebi.biostd.submission.exceptions.ProjectAlreadyExistingException -import ac.uk.ebi.biostd.submission.exceptions.ProjectInvalidAccNoPatternException -import ac.uk.ebi.biostd.submission.exceptions.UserCanNotSubmitProjectsException -import ac.uk.ebi.biostd.submission.test.createBasicExtendedSubmission -import ac.uk.ebi.biostd.submission.test.createBasicProject -import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil -import ebi.ac.uk.persistence.PersistenceContext -import ebi.ac.uk.security.integration.components.IUserPrivilegesService -import io.mockk.clearAllMocks -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.verify -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.api.extension.ExtendWith - -@ExtendWith(MockKExtension::class) -class ProjectValidationServiceTest( - @MockK private val accNoPatternUtil: AccNoPatternUtil, - @MockK private val persistenceContext: PersistenceContext, - @MockK private val userPrivilegesService: IUserPrivilegesService -) { - private val project = createBasicProject() - private val testInstance = ProjectValidationService(persistenceContext, accNoPatternUtil, userPrivilegesService) - - @BeforeEach - fun beforeEach() { - every { persistenceContext.isNew("ABC456") } returns true - every { accNoPatternUtil.isPattern("!{S-ABC}") } returns true - every { persistenceContext.accessTagExists("ABC456") } returns false - every { userPrivilegesService.canSubmitProjects("user@mail.com") } returns true - } - - @AfterEach - fun afterEach() = clearAllMocks() - - @Test - fun validate() { - testInstance.validate(project) - verify(exactly = 1) { - persistenceContext.isNew("ABC456") - accNoPatternUtil.isPattern("!{S-ABC}") - persistenceContext.accessTagExists("ABC456") - userPrivilegesService.canSubmitProjects("user@mail.com") - } - } - - @Test - fun `user cannot submit`() { - every { userPrivilegesService.canSubmitProjects("user@mail.com") } returns false - - val error = - assertThrows { testInstance.validate(project) } - assertThat(error.message).isEqualTo("The user user@mail.com is not allowed to submit projects") - - verify(exactly = 1) { userPrivilegesService.canSubmitProjects("user@mail.com") } - verify(exactly = 0) { accNoPatternUtil.isPattern("!{S-ABC}") } - verify(exactly = 0) { - persistenceContext.isNew("ABC456") - persistenceContext.accessTagExists("ABC456") - } - } - - @Test - fun `missing acc no pattern`() { - val error = assertThrows { - testInstance.validate(createBasicExtendedSubmission()) - } - assertThat(error.message).isEqualTo(ACC_NO_TEMPLATE_REQUIRED) - - verify(exactly = 1) { userPrivilegesService.canSubmitProjects("user@mail.com") } - verify(exactly = 0) { - persistenceContext.isNew("ABC456") - persistenceContext.accessTagExists("ABC456") - } - } - - @Test - fun `invalid acc no pattern`() { - every { accNoPatternUtil.isPattern("!{S-ABC}") } returns false - - val error = assertThrows { - testInstance.validate(project) - } - assertThat(error.message).isEqualTo(ACC_NO_TEMPLATE_INVALID) - - verify(exactly = 1) { userPrivilegesService.canSubmitProjects("user@mail.com") } - verify(exactly = 0) { - persistenceContext.isNew("ABC456") - persistenceContext.accessTagExists("ABC456") - } - } - - @Test - fun `already existing project`() { - every { persistenceContext.isNew("ABC456") } returns false - - val error = assertThrows { testInstance.validate(project) } - assertThat(error.message).isEqualTo("The project ABC456 already exists") - - verify(exactly = 0) { persistenceContext.accessTagExists("ABC456") } - verify(exactly = 1) { accNoPatternUtil.isPattern("!{S-ABC}") } - verify(exactly = 1) { - persistenceContext.isNew("ABC456") - userPrivilegesService.canSubmitProjects("user@mail.com") - } - } - - @Test - fun `already existing tag`() { - every { persistenceContext.accessTagExists("ABC456") } returns true - - val error = assertThrows { - testInstance.validate(project) - } - assertThat(error.message).isEqualTo("The access tag with name ABC456 already exists") - - verify(exactly = 1) { - persistenceContext.isNew("ABC456") - persistenceContext.accessTagExists("ABC456") - userPrivilegesService.canSubmitProjects("user@mail.com") - } - } -} diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/TimesServiceTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/TimesServiceTest.kt index f0027e570d..9a2f776aaf 100644 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/TimesServiceTest.kt +++ b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/service/TimesServiceTest.kt @@ -1,11 +1,8 @@ package ac.uk.ebi.biostd.submission.service +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.submission.exceptions.InvalidDateFormatException import ac.uk.ebi.biostd.submission.test.ACC_NO -import ac.uk.ebi.biostd.submission.test.createBasicExtendedSubmission -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.extensions.releaseDate -import ebi.ac.uk.persistence.PersistenceContext import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension @@ -21,25 +18,22 @@ import java.time.ZoneOffset @ExtendWith(MockKExtension::class) class TimesServiceTest(@MockK private val mockContext: PersistenceContext) { - private lateinit var submission: ExtendedSubmission private val testInstance = TimesService(mockContext) private val testTime = OffsetDateTime.of(2018, 10, 10, 0, 0, 0, 0, ZoneOffset.UTC) private val mockNow = OffsetDateTime.of(2018, 12, 31, 0, 0, 0, 0, ZoneOffset.UTC) @BeforeEach fun beforeEach() { - submission = createBasicExtendedSubmission() - mockkStatic(OffsetDateTime::class) every { OffsetDateTime.now() } returns mockNow - every { mockContext.getSubmission(ACC_NO) } returns null + every { mockContext.findCreationTime(ACC_NO) } returns null } @Nested inner class ModificationTime { @Test fun `calculate modification time`() { - val times = testInstance.getTimes(submission) + val times = testInstance.getTimes(TimesRequest(ACC_NO)) assertThat(times.modificationTime).isEqualTo(mockNow) } } @@ -48,16 +42,15 @@ class TimesServiceTest(@MockK private val mockContext: PersistenceContext) { inner class CreationTime { @Test fun `when exists`() { - val existingSubmission = createBasicExtendedSubmission().apply { creationTime = testTime } - every { mockContext.getSubmission(ACC_NO) } returns existingSubmission + every { mockContext.findCreationTime(ACC_NO) } returns testTime - val times = testInstance.getTimes(submission) + val times = testInstance.getTimes(TimesRequest(ACC_NO)) assertThat(times.createTime).isEqualTo(testTime) } @Test fun `when is new`() { - val times = testInstance.getTimes(submission) + val times = testInstance.getTimes(TimesRequest(ACC_NO)) assertThat(times.createTime).isEqualTo(mockNow) } } @@ -66,9 +59,9 @@ class TimesServiceTest(@MockK private val mockContext: PersistenceContext) { inner class ReleaseTime { @Test fun `when release date with invalid format`() { - submission.releaseDate = "2018/10/10" - - val exception = assertThrows { testInstance.getTimes(submission) } + val exception = assertThrows { + testInstance.getTimes(TimesRequest(ACC_NO, "2018/10/10")) + } assertThat(exception.message).isEqualTo( "Provided date 2018/10/10 could not be parsed. Expected format is YYYY-MM-DD") @@ -77,15 +70,14 @@ class TimesServiceTest(@MockK private val mockContext: PersistenceContext) { @Test fun `when release date with valid format`() { val releaseTime = OffsetDateTime.of(2019, 10, 10, 0, 0, 0, 0, ZoneOffset.UTC) - submission.releaseDate = "2019-10-10T09:27:04.000Z" + val times = testInstance.getTimes(TimesRequest(ACC_NO, "2019-10-10T09:27:04.000Z")) - val times = testInstance.getTimes(submission) assertThat(times.releaseTime).isEqualTo(releaseTime) } @Test fun `when no release date`() { - val times = testInstance.getTimes(submission) + val times = testInstance.getTimes(TimesRequest(ACC_NO)) assertThat(times.releaseTime).isNull() } } diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/submitter/ProjectSubmitterTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/submitter/ProjectSubmitterTest.kt deleted file mode 100644 index 7a60a095c6..0000000000 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/submitter/ProjectSubmitterTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -package ac.uk.ebi.biostd.submission.submitter - -import ac.uk.ebi.biostd.submission.service.ProjectValidationService -import ac.uk.ebi.biostd.submission.service.TimesService -import ac.uk.ebi.biostd.submission.test.createBasicProject -import ac.uk.ebi.biostd.submission.util.AccNoPatternUtil -import ebi.ac.uk.model.constants.ProcessingStatus.PROCESSED -import ebi.ac.uk.persistence.PersistenceContext -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.verify -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith - -@Disabled -@ExtendWith(MockKExtension::class) -class ProjectSubmitterTest( - @MockK private val timesService: TimesService, - @MockK private val accNoPatternUtil: AccNoPatternUtil, - @MockK private val persistenceContext: PersistenceContext, - @MockK private val projectValidationService: ProjectValidationService -) { - private val project = createBasicProject() - private val testInstance = - ProjectSubmitter(timesService, accNoPatternUtil, persistenceContext, projectValidationService) - - @BeforeEach - fun beforeEach() { - every { accNoPatternUtil.getPattern("!{S-ABC}") } returns "S-ABC" - every { persistenceContext.saveAccessTag("ABC456") } answers { nothing } - every { persistenceContext.saveSubmission(project) } answers { project } - every { projectValidationService.validate(project) } answers { nothing } - every { persistenceContext.createAccNoPatternSequence("S-ABC") } answers { nothing } - } - - @Test - fun submit() { - testInstance.submit(project) - - assertThat(project.processingStatus).isEqualTo(PROCESSED) - verify(exactly = 1) { - accNoPatternUtil.getPattern("!{S-ABC}") - projectValidationService.validate(project) - persistenceContext.saveSubmission(project) - persistenceContext.saveAccessTag("ABC456") - persistenceContext.createAccNoPatternSequence("S-ABC") - } - } -} diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/submitter/SubmissionSubmitterTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/submitter/SubmissionSubmitterTest.kt deleted file mode 100644 index 76abb714a7..0000000000 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/submitter/SubmissionSubmitterTest.kt +++ /dev/null @@ -1,80 +0,0 @@ -package ac.uk.ebi.biostd.submission.submitter - -import ac.uk.ebi.biostd.submission.handlers.FilesHandler -import ac.uk.ebi.biostd.submission.model.SubmissionRequest -import ac.uk.ebi.biostd.submission.service.AccNoService -import ac.uk.ebi.biostd.submission.service.Times -import ac.uk.ebi.biostd.submission.service.TimesService -import ac.uk.ebi.biostd.submission.test.createBasicExtendedSubmission -import ebi.ac.uk.io.sources.FilesSource -import ebi.ac.uk.model.AccNumber -import ebi.ac.uk.model.ExtendedSubmission -import ebi.ac.uk.model.constants.ProcessingStatus -import ebi.ac.uk.persistence.PersistenceContext -import ebi.ac.uk.security.integration.model.api.SecurityUser -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.slot -import io.mockk.verify -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import java.time.OffsetDateTime -import java.time.ZoneOffset - -@ExtendWith(MockKExtension::class) -class SubmissionSubmitterTest( - @MockK private val filesSource: FilesSource, - @MockK private val filesHandler: FilesHandler, - @MockK private val timesService: TimesService, - @MockK private val accNoService: AccNoService, - @MockK private val persistenceContext: PersistenceContext, - @MockK private val submissionRequest: SubmissionRequest, - @MockK private val user: SecurityUser -) { - private val submission = createBasicExtendedSubmission() - private val savedSubmission = slot() - - private val testAccNo = AccNumber("ABC", 456) - private val testTime = OffsetDateTime.of(2018, 10, 10, 0, 0, 0, 0, ZoneOffset.UTC) - private val testInstance = SubmissionSubmitter(filesHandler, timesService, accNoService, persistenceContext) - - @BeforeEach - fun beforeEach() { - every { submissionRequest.files } answers { filesSource } - every { submissionRequest.submission } answers { submission.asSubmission() } - every { submissionRequest.user } answers { user } - every { submissionRequest.method } answers { null } - - every { accNoService.getAccNo(submission) } returns testAccNo - every { accNoService.getRelPath(testAccNo) } returns "ABC/ABCxxx456/ABC456" - - every { persistenceContext.isNew("ABC456") } returns false - every { persistenceContext.getSecret("ABC456") } returns "a-secret-key" - every { persistenceContext.getParentAccessTags(submission) } returns emptyList() - every { persistenceContext.deleteSubmissionDrafts(submission) } answers { nothing } - every { persistenceContext.saveSubmission(capture(savedSubmission)) } answers { submission } - - every { timesService.getTimes(submission) } returns Times(testTime, testTime, testTime) - every { filesHandler.processFiles(submission, filesSource) } answers { nothing } - every { user.asUser() } answers { submission.user } - } - - @Test - fun submit() { - testInstance.submit(submissionRequest) - - assertThat(savedSubmission.captured.processingStatus).isEqualTo(ProcessingStatus.PROCESSED) - verify(exactly = 1) { - timesService.getTimes(submission) - accNoService.getAccNo(submission) - accNoService.getRelPath(testAccNo) - persistenceContext.saveSubmission(submission) - persistenceContext.deleteSubmissionDrafts(submission) - persistenceContext.getParentAccessTags(submission) - filesHandler.processFiles(submission, filesSource) - } - } -} diff --git a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/util/AccNoPatternUtilTest.kt b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/util/AccNoPatternUtilTest.kt index 4e6fdbff79..938ddc4fee 100644 --- a/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/util/AccNoPatternUtilTest.kt +++ b/submission/submitter/src/test/kotlin/ac/uk/ebi/biostd/submission/util/AccNoPatternUtilTest.kt @@ -1,8 +1,8 @@ package ac.uk.ebi.biostd.submission.util +import ac.uk.ebi.biostd.persistence.integration.PersistenceContext import ac.uk.ebi.biostd.submission.exceptions.InvalidAccNoPattern import ac.uk.ebi.biostd.submission.exceptions.InvalidPatternException -import ebi.ac.uk.persistence.PersistenceContext import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension