diff --git a/client/bio-commandline/src/test/kotlin/uk/ac/ebi/biostd/client/cli/services/SubmissionServiceTest.kt b/client/bio-commandline/src/test/kotlin/uk/ac/ebi/biostd/client/cli/services/SubmissionServiceTest.kt index b5c2fb797..e83a1e5b9 100644 --- a/client/bio-commandline/src/test/kotlin/uk/ac/ebi/biostd/client/cli/services/SubmissionServiceTest.kt +++ b/client/bio-commandline/src/test/kotlin/uk/ac/ebi/biostd/client/cli/services/SubmissionServiceTest.kt @@ -54,7 +54,7 @@ internal class SubmissionServiceTest { testInstance.submit(subRequest) - verify(exactly = 0) { bioWebClient.getSubmissionRequestStatus(any(), any()) } + coVerify(exactly = 0) { bioWebClient.getSubmissionRequestStatus(any(), any()) } verify(exactly = 1) { create(SERVER).getAuthenticatedClient(USER, PASSWORD, ON_BEHALF) bioWebClient.submitMultipartAsync( @@ -69,7 +69,7 @@ internal class SubmissionServiceTest { runTest { val accepted = AcceptedSubmission("S-BSST1", 2) - every { bioWebClient.getSubmissionRequestStatus("S-BSST1", 2) } returns PROCESSED + coEvery { bioWebClient.getSubmissionRequestStatus("S-BSST1", 2) } returns PROCESSED every { create(SERVER).getAuthenticatedClient(USER, PASSWORD, ON_BEHALF) } returns bioWebClient every { bioWebClient.submitMultipartAsync(subRequest.submissionFile, subRequest.parameters) @@ -77,7 +77,7 @@ internal class SubmissionServiceTest { testInstance.submit(subRequest.copy(await = true)) - verify(exactly = 1) { + coVerify(exactly = 1) { create(SERVER).getAuthenticatedClient(USER, PASSWORD, ON_BEHALF) bioWebClient.getSubmissionRequestStatus("S-BSST1", 2) bioWebClient.submitMultipartAsync( diff --git a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionRequestClient.kt b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionRequestClient.kt index 2d7d42ab3..4365d41e3 100644 --- a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionRequestClient.kt +++ b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/api/SubmissionRequestClient.kt @@ -1,19 +1,35 @@ package ac.uk.ebi.biostd.client.api import ac.uk.ebi.biostd.client.integration.web.SubmissionRequestOperations -import ebi.ac.uk.commons.http.ext.getForObject import ebi.ac.uk.model.RequestStatus +import kotlinx.coroutines.reactive.awaitSingle import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.reactive.function.client.awaitBody private const val SUBMISSION_REQUEST_URL = "/submissions/requests" class SubmissionRequestClient( private val client: WebClient, ) : SubmissionRequestOperations { - override fun getSubmissionRequestStatus( + override suspend fun getSubmissionRequestStatus( accNo: String, version: Int, - ): RequestStatus { - return client.getForObject("$SUBMISSION_REQUEST_URL/$accNo/$version/status") + ): RequestStatus = + client + .post() + .uri("$SUBMISSION_REQUEST_URL/$accNo/$version/status") + .retrieve() + .awaitBody() + + override suspend fun archiveSubmissionRequest( + accNo: String, + version: Int, + ) { + client + .post() + .uri("$SUBMISSION_REQUEST_URL/$accNo/$version/archive") + .retrieve() + .bodyToMono(Void::class.java) + .awaitSingle() } } diff --git a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmitClient.kt b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmitClient.kt index e5e54628a..40a187521 100644 --- a/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmitClient.kt +++ b/client/bio-webclient/src/main/kotlin/ac/uk/ebi/biostd/client/integration/web/SubmitClient.kt @@ -303,8 +303,13 @@ interface MultipartAsyncSubmitOperations { } interface SubmissionRequestOperations { - fun getSubmissionRequestStatus( + suspend fun getSubmissionRequestStatus( accNo: String, version: Int, ): RequestStatus + + suspend fun archiveSubmissionRequest( + accNo: String, + version: Int, + ) } diff --git a/commons/commons-test/src/main/kotlin/ebi/ac/uk/db/DatabaseConstants.kt b/commons/commons-test/src/main/kotlin/ebi/ac/uk/db/DatabaseConstants.kt index 1b9675a40..e1494be4d 100644 --- a/commons/commons-test/src/main/kotlin/ebi/ac/uk/db/DatabaseConstants.kt +++ b/commons/commons-test/src/main/kotlin/ebi/ac/uk/db/DatabaseConstants.kt @@ -1,6 +1,6 @@ package ebi.ac.uk.db -const val MONGO_VERSION = "mongo:4.0.10" +const val MONGO_VERSION = "mongo:4.4.22" const val RABBIT_VERSION = "rabbitmq:3.7.25-management-alpine" const val MYSQL_VERSION = "mysql:5.7.33" const val MYSQL_SCHEMA = "Schema.sql" diff --git a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/service/SubmissionOperations.kt b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/service/SubmissionOperations.kt index 8dc4317e7..d01afe787 100644 --- a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/service/SubmissionOperations.kt +++ b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/service/SubmissionOperations.kt @@ -127,6 +127,11 @@ interface SubmissionRequestPersistenceService { accNo: String, version: Int, ): Boolean + + suspend fun archiveRequest( + accNo: String, + version: Int, + ) } sealed interface OptResponse { diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt index 6891726b7..78359bb9c 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt @@ -168,3 +168,9 @@ object DocRequestFields { const val RQT_STATUS_CHANGE_END_TIME = "endTime" const val RQT_STATUS_CHANGE_RESULT = "result" } + +object DocRequestFileFields { + const val RQT_FILE_ACC_NO = "accNo" + const val RQT_FILE_VERSION = "version" + const val RQT_FILE_PATH = "path" +} diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepository.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepository.kt index bc8251c22..8ac5f12b7 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepository.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepository.kt @@ -38,21 +38,33 @@ import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocSubmissionReques import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocSubmissionRequestFileFields.RQT_FILE_SUB_VERSION import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocSubmissionRequestFileFields.RQT_PREVIOUS_SUB_FILE import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestRepository +import ac.uk.ebi.biostd.persistence.doc.model.CollectionsNames.RQT_ARCH_COL +import ac.uk.ebi.biostd.persistence.doc.model.CollectionsNames.RQT_FILE_ARCH_COL import ac.uk.ebi.biostd.persistence.doc.model.DocRequestStatusChanges import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequest import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequestFile import com.google.common.collect.ImmutableList import com.mongodb.BasicDBObject +import ebi.ac.uk.coroutines.every import ebi.ac.uk.model.RequestStatus import ebi.ac.uk.model.RequestStatus.Companion.PROCESSING import ebi.ac.uk.model.RequestStatus.PROCESSED +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.count import kotlinx.coroutines.flow.toList import kotlinx.coroutines.reactive.asFlow +import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactor.awaitSingle import kotlinx.coroutines.reactor.awaitSingleOrNull import org.bson.types.ObjectId import org.springframework.data.mongodb.core.FindAndModifyOptions import org.springframework.data.mongodb.core.ReactiveMongoTemplate +import org.springframework.data.mongodb.core.aggregation.Aggregation +import org.springframework.data.mongodb.core.aggregation.Aggregation.match +import org.springframework.data.mongodb.core.aggregation.AggregationOptions +import org.springframework.data.mongodb.core.aggregation.Fields +import org.springframework.data.mongodb.core.aggregation.MergeOperation.WhenDocumentsDontMatch +import org.springframework.data.mongodb.core.aggregation.MergeOperation.WhenDocumentsMatch import org.springframework.data.mongodb.core.query.Criteria import org.springframework.data.mongodb.core.query.Criteria.where import org.springframework.data.mongodb.core.query.Query @@ -69,15 +81,77 @@ class SubmissionRequestDocDataRepository( ) : SubmissionRequestRepository by submissionRequestRepository { suspend fun saveRequest(request: DocSubmissionRequest): Pair { val result = - mongoTemplate.upsert( - Query(where(RQT_ACC_NO).`is`(request.accNo).andOperator(where(RQT_STATUS).ne(PROCESSED))), - request.asSetOnInsert(), - DocSubmissionRequest::class.java, - ).awaitSingle() + mongoTemplate + .upsert( + Query(where(RQT_ACC_NO).`is`(request.accNo).andOperator(where(RQT_STATUS).ne(PROCESSED))), + request.asSetOnInsert(), + DocSubmissionRequest::class.java, + ).awaitSingle() val created = result.matchedCount < 1 return submissionRequestRepository.getByAccNoAndStatusIn(request.accNo, PROCESSING) to created } + suspend fun archiveRequest( + accNo: String, + version: Int, + ): Int { + val matchOperation = + match( + where(RQT_FILE_SUB_ACC_NO) + .`is`(accNo) + .andOperator(where(RQT_FILE_SUB_VERSION).`is`(version)), + ) + + fun archiveRequestFiles(): Flow { + var mergeOperation = + Aggregation + .merge() + .intoCollection(RQT_FILE_ARCH_COL) + .on(Fields.UNDERSCORE_ID) + .whenMatched(WhenDocumentsMatch.replaceDocument()) + .whenNotMatched(WhenDocumentsDontMatch.insertNewDocument()) + .build() + val aggregation = + Aggregation + .newAggregation( + DocSubmissionRequestFile::class.java, + matchOperation, + mergeOperation, + ).withOptions(AggregationOptions.builder().allowDiskUse(true).build()) + return mongoTemplate + .aggregate(aggregation, DocSubmissionRequestFile::class.java) + .asFlow() + } + + suspend fun archiveRequest(): DocSubmissionRequest { + var mergeOperation = + Aggregation + .merge() + .intoCollection(RQT_ARCH_COL) + .on(Fields.UNDERSCORE_ID) + .whenMatched(WhenDocumentsMatch.replaceDocument()) + .whenNotMatched(WhenDocumentsDontMatch.insertNewDocument()) + .build() + val aggregation = + Aggregation + .newAggregation( + DocSubmissionRequest::class.java, + matchOperation, + mergeOperation, + ).withOptions(AggregationOptions.builder().allowDiskUse(true).build()) + return mongoTemplate + .aggregate(aggregation, DocSubmissionRequest::class.java) + .awaitSingle() + } + + val archivedFiles = + archiveRequestFiles() + .every(REPORT_RATE) { "$accNo, $version archived file ${it.index}, path='${it.value.path}'" } + .count() + archiveRequest() + return archivedFiles + } + suspend fun findActiveRequests(filter: SubmissionListFilter): Pair> { val query = Query().addCriteria(createQuery(filter)) val requestCount = mongoTemplate.count(query, DocSubmissionRequest::class.java).awaitSingle() @@ -90,9 +164,7 @@ class SubmissionRequestDocDataRepository( suspend fun getRequest( accNo: String, version: Int, - ): DocSubmissionRequest { - return submissionRequestRepository.getByAccNoAndVersion(accNo, version) - } + ): DocSubmissionRequest = submissionRequestRepository.getByAccNoAndVersion(accNo, version) suspend fun getRequest( accNo: String, @@ -111,14 +183,23 @@ class SubmissionRequestDocDataRepository( result = null, ) val update = Update().addToSet(RQT_STATUS_CHANGES, statusChange) - val query = Query(where(RQT_ACC_NO).`is`(accNo).and(RQT_VERSION).`is`(version).and(RQT_STATUS).`is`(status)) + val query = + Query( + where(RQT_ACC_NO) + .`is`(accNo) + .and(RQT_VERSION) + .`is`(version) + .and(RQT_STATUS) + .`is`(status), + ) val result = - mongoTemplate.findAndModify( - query, - update, - FindAndModifyOptions.options().returnNew(true), - DocSubmissionRequest::class.java, - ).awaitSingle() + mongoTemplate + .findAndModify( + query, + update, + FindAndModifyOptions.options().returnNew(true), + DocSubmissionRequest::class.java, + ).awaitSingle() return statusId.toString() to result } @@ -128,7 +209,8 @@ class SubmissionRequestDocDataRepository( limit: Int, ): Pair> { val result = - mongoTemplate.find(query.skip(skip).limit(limit), DocSubmissionRequest::class.java) + mongoTemplate + .find(query.skip(skip).limit(limit), DocSubmissionRequest::class.java) .asFlow() .toList() return result.count() to result @@ -136,7 +218,8 @@ class SubmissionRequestDocDataRepository( @Suppress("SpreadOperator") private fun createQuery(filter: SubmissionListFilter): Criteria = - where("$SUB.$SUB_OWNER").`is`(filter.filterUser) + where("$SUB.$SUB_OWNER") + .`is`(filter.filterUser) .andOperator(*criteriaArray(filter)) suspend fun increaseIndex( @@ -155,7 +238,8 @@ class SubmissionRequestDocDataRepository( .set(RQT_FILE_INDEX, file.index) .set(RQT_FILE_STATUS, file.status) val where = - where(RQT_FILE_SUB_ACC_NO).`is`(file.accNo) + where(RQT_FILE_SUB_ACC_NO) + .`is`(file.accNo) .andOperator( where(RQT_FILE_SUB_VERSION).`is`(file.version), where(RQT_FILE_PATH).`is`(file.path), @@ -169,7 +253,8 @@ class SubmissionRequestDocDataRepository( val serializedFile = extSerializationService.serialize(file.file) val update = update(RQT_FILE_FILE, BasicDBObject.parse(serializedFile)).set(RQT_FILE_STATUS, file.status) val where = - where(RQT_FILE_SUB_ACC_NO).`is`(file.accNo) + where(RQT_FILE_SUB_ACC_NO) + .`is`(file.accNo) .andOperator( where(RQT_FILE_SUB_VERSION).`is`(file.version), where(RQT_FILE_PATH).`is`(file.path), @@ -201,8 +286,12 @@ class SubmissionRequestDocDataRepository( ) { val query = Query( - where(SUB_ACC_NO).`is`(rqt.accNo).and(SUB_VERSION).`is`(rqt.version) - .and("$RQT_STATUS_CHANGES.$RQT_STATUS_CHANGE_STATUS_ID").`is`(ObjectId(processId)), + where(SUB_ACC_NO) + .`is`(rqt.accNo) + .and(SUB_VERSION) + .`is`(rqt.version) + .and("$RQT_STATUS_CHANGES.$RQT_STATUS_CHANGE_STATUS_ID") + .`is`(ObjectId(processId)), ) val update = Update() @@ -222,15 +311,18 @@ class SubmissionRequestDocDataRepository( } private fun criteriaArray(filter: SubmissionListFilter): Array = - ImmutableList.Builder().apply { - add(where(SUB_STATUS).`in`(PROCESSING)) - filter.accNo?.let { add(where("$SUB.$SUB_ACC_NO").`is`(it)) } - filter.type?.let { add(where("$SUB.$SUB_SECTION.$SEC_TYPE").`is`(it)) } - filter.rTimeFrom?.let { add(where("$SUB.$SUB_RELEASE_TIME").gte(it.toString())) } - filter.rTimeTo?.let { add(where("$SUB.$SUB_RELEASE_TIME").lte(it.toString())) } - filter.keywords?.let { add(keywordsCriteria(it)) } - filter.released?.let { add(where("$SUB.$SUB_RELEASED").`is`(it)) } - }.build().toTypedArray() + ImmutableList + .Builder() + .apply { + add(where(SUB_STATUS).`in`(PROCESSING)) + filter.accNo?.let { add(where("$SUB.$SUB_ACC_NO").`is`(it)) } + filter.type?.let { add(where("$SUB.$SUB_SECTION.$SEC_TYPE").`is`(it)) } + filter.rTimeFrom?.let { add(where("$SUB.$SUB_RELEASE_TIME").gte(it.toString())) } + filter.rTimeTo?.let { add(where("$SUB.$SUB_RELEASE_TIME").lte(it.toString())) } + filter.keywords?.let { add(keywordsCriteria(it)) } + filter.released?.let { add(where("$SUB.$SUB_RELEASED").`is`(it)) } + }.build() + .toTypedArray() private fun keywordsCriteria(keywords: String) = Criteria().orOperator( @@ -239,6 +331,10 @@ class SubmissionRequestDocDataRepository( where(ATTRIBUTE_DOC_NAME).`is`("Title").and(ATTRIBUTE_DOC_VALUE).regex("(?i).*$keywords.*"), ), ) + + companion object { + const val REPORT_RATE = 200 + } } enum class ProcessResult { diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestFilesDocDataRepository.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestFilesDocDataRepository.kt new file mode 100644 index 000000000..4ed9811ba --- /dev/null +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestFilesDocDataRepository.kt @@ -0,0 +1,7 @@ +package ac.uk.ebi.biostd.persistence.doc.db.data + +import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestFilesRepository + +class SubmissionRequestFilesDocDataRepository( + private val submissionRequestFilesRepository: SubmissionRequestFilesRepository, +) : SubmissionRequestFilesRepository by submissionRequestFilesRepository diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/reactive/repositories/Repositories.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/reactive/repositories/Repositories.kt index bc2ddb3e6..d6f7d4916 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/reactive/repositories/Repositories.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/reactive/repositories/Repositories.kt @@ -94,9 +94,8 @@ interface SubmissionMongoRepository : CoroutineCrudRepository { suspend fun existsByAccNoAndStatusIn( @@ -130,6 +129,11 @@ interface SubmissionRequestRepository : CoroutineCrudRepository + + suspend fun deleteByAccNoAndVersion( + accNo: String, + version: Int, + ) } interface SubmissionRequestFilesRepository : CoroutineCrudRepository { @@ -145,6 +149,11 @@ interface SubmissionRequestFilesRepository : CoroutineCrudRepository + suspend fun countByAccNoAndVersion( + accNo: String, + version: Int, + ): Int + @Query("{ 'accNo': ?0, 'version': ?1, 'status': ?2 }") @Meta(flags = [CursorOption.NO_TIMEOUT]) fun findRequestFiles( @@ -159,6 +168,11 @@ interface SubmissionRequestFilesRepository : CoroutineCrudRepository { diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbReposConfig.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbReposConfig.kt index 30afb7d7e..d8b4f630b 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbReposConfig.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbReposConfig.kt @@ -5,10 +5,12 @@ import ac.uk.ebi.biostd.persistence.doc.db.data.FileListDocFileDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionDraftDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestDocDataRepository +import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestFilesDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionStatsDataRepository import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.FileListDocFileRepository import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionDraftRepository import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionMongoRepository +import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestFilesRepository import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestRepository import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionStatsRepository import org.springframework.context.annotation.Bean @@ -44,6 +46,11 @@ class MongoDbReposConfig { submissionRequestRepository, ) + @Bean + internal fun submissionRequestFilesDocDataRepository( + submissionRequestFilesRepository: SubmissionRequestFilesRepository, + ): SubmissionRequestFilesDocDataRepository = SubmissionRequestFilesDocDataRepository(submissionRequestFilesRepository) + @Bean internal fun submissionDraftDocDataRepository( reactivateMongoTemplate: ReactiveMongoTemplate, diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbServicesConfig.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbServicesConfig.kt index 1dd766d79..451e3d8ca 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbServicesConfig.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/integration/MongoDbServicesConfig.kt @@ -11,8 +11,8 @@ import ac.uk.ebi.biostd.persistence.doc.db.data.FileListDocFileDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionDraftDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestDocDataRepository +import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestFilesDocDataRepository import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionStatsDataRepository -import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestFilesRepository import ac.uk.ebi.biostd.persistence.doc.mapping.to.ToExtSubmissionMapper import ac.uk.ebi.biostd.persistence.doc.service.CollectionMongoDataService import ac.uk.ebi.biostd.persistence.doc.service.DistributedLockService @@ -60,15 +60,21 @@ class MongoDbServicesConfig { internal fun submissionRequestPersistenceService( serializationService: ExtSerializationService, requestRepo: SubmissionRequestDocDataRepository, + requestFilesRepository: SubmissionRequestFilesDocDataRepository, distributedLockService: DistributedLockService, ): SubmissionRequestPersistenceService = - SubmissionRequestMongoPersistenceService(serializationService, requestRepo, distributedLockService) + SubmissionRequestMongoPersistenceService( + serializationService, + requestRepo, + requestFilesRepository, + distributedLockService, + ) @Bean internal fun submissionRequestFilesPersistenceService( extSerializationService: ExtSerializationService, requestRepository: SubmissionRequestDocDataRepository, - requestFilesRepository: SubmissionRequestFilesRepository, + requestFilesRepository: SubmissionRequestFilesDocDataRepository, ): SubmissionRequestFilesPersistenceService = SubmissionRequestFilesMongoPersistenceService( extSerializationService, diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt index 1ec0ef885..832d15f2e 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt @@ -2,6 +2,8 @@ package ac.uk.ebi.biostd.persistence.doc.model import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocRequestFields +import ac.uk.ebi.biostd.persistence.doc.model.CollectionsNames.RQT_COL +import ac.uk.ebi.biostd.persistence.doc.model.CollectionsNames.RQT_FILE_COL import com.mongodb.DBObject import ebi.ac.uk.model.RequestStatus import org.bson.types.ObjectId @@ -10,7 +12,7 @@ import org.springframework.data.mongodb.core.mapping.Document import org.springframework.data.mongodb.core.query.Update import java.time.Instant -@Document(collection = "submission_requests") +@Document(collection = RQT_COL) data class DocSubmissionRequest( @Id val id: ObjectId, @@ -63,7 +65,7 @@ data class DocRequestStatusChanges( val result: String?, ) -@Document(collection = "submission_request_files") +@Document(collection = RQT_FILE_COL) data class DocSubmissionRequestFile( @Id val id: ObjectId, @@ -75,3 +77,11 @@ data class DocSubmissionRequestFile( val status: RequestFileStatus, val previousSubFile: Boolean, ) + +object CollectionsNames { + const val RQT_FILE_COL = "submission_request_files" + const val RQT_FILE_ARCH_COL = "submission_request_files_archive" + + const val RQT_COL = "submission_requests" + const val RQT_ARCH_COL = "submission_requests_archive" +} diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceService.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceService.kt index 90f25ad98..1a7286127 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceService.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceService.kt @@ -4,7 +4,7 @@ import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestDocDataRepository -import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestFilesRepository +import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestFilesDocDataRepository import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequestFile import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -13,7 +13,7 @@ import uk.ac.ebi.extended.serialization.service.ExtSerializationService class SubmissionRequestFilesMongoPersistenceService( private val extSerializationService: ExtSerializationService, private val requestRepository: SubmissionRequestDocDataRepository, - private val requestFilesRepository: SubmissionRequestFilesRepository, + private val requestFilesRepository: SubmissionRequestFilesDocDataRepository, ) : SubmissionRequestFilesPersistenceService { override suspend fun saveSubmissionRequestFile(file: SubmissionRequestFile) { requestRepository.upsertSubRqtFile(file) @@ -23,31 +23,28 @@ class SubmissionRequestFilesMongoPersistenceService( accNo: String, version: Int, filePath: String, - ): SubmissionRequestFile { - return requestFilesRepository + ): SubmissionRequestFile = + requestFilesRepository .getByPathAndAccNoAndVersion(filePath, accNo, version) .toSubmissionRequestFile() - } override fun getSubmissionRequestFiles( accNo: String, version: Int, startingAt: Int, - ): Flow { - return requestFilesRepository + ): Flow = + requestFilesRepository .findRequestFiles(accNo, version, startingAt) .map { it.toSubmissionRequestFile() } - } override fun getSubmissionRequestFiles( accNo: String, version: Int, status: RequestFileStatus, - ): Flow { - return requestFilesRepository + ): Flow = + requestFilesRepository .findRequestFiles(accNo, version, status) .map { it.toSubmissionRequestFile() } - } private fun DocSubmissionRequestFile.toSubmissionRequestFile(): SubmissionRequestFile { val file = extSerializationService.deserializeFile(file.toString()) diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt index 842833e17..0476cb38a 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt @@ -7,6 +7,7 @@ import ac.uk.ebi.biostd.persistence.common.service.OptResponse import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService import ac.uk.ebi.biostd.persistence.doc.db.data.ProcessResult import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestDocDataRepository +import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestFilesDocDataRepository import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequest import com.mongodb.BasicDBObject import ebi.ac.uk.model.RequestStatus @@ -30,6 +31,7 @@ private val logger = KotlinLogging.logger {} class SubmissionRequestMongoPersistenceService( private val serializationService: ExtSerializationService, private val requestRepository: SubmissionRequestDocDataRepository, + private val requestFilesRepository: SubmissionRequestFilesDocDataRepository, private val distributedLockService: DistributedLockService, ) : SubmissionRequestPersistenceService { override suspend fun hasActiveRequest(accNo: String): Boolean = requestRepository.existsByAccNoAndStatusIn(accNo, PROCESSING) @@ -47,6 +49,22 @@ class SubmissionRequestMongoPersistenceService( return request.map { it.accNo to it.version } } + override suspend fun archiveRequest( + accNo: String, + version: Int, + ) { + require( + requestRepository.existsByAccNoAndVersionAndStatus(accNo, version, PROCESSED), + ) { "Request $accNo, $version can not be archived as not processed" } + + val archivedFiles = requestRepository.archiveRequest(accNo, version) + val countFiles = requestFilesRepository.countByAccNoAndVersion(accNo, version) + + if (archivedFiles != countFiles) error("More files that archived identitified in request $accNo, $version") + requestRepository.deleteByAccNoAndVersion(accNo, version) + requestFilesRepository.deleteByAccNoAndVersion(accNo, version) + } + override suspend fun createRequest(rqt: SubmissionRequest): Pair { val (request, created) = requestRepository.saveRequest(asDocRequest(rqt)) if (created.not()) throw ConcurrentSubException(request.accNo, request.version) diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt index 189c8fc5e..63805711b 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt @@ -1,8 +1,14 @@ package ac.uk.ebi.biostd.persistence.doc.db.data +import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus import ac.uk.ebi.biostd.persistence.common.model.action +import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocRequestFields.RQT_ACC_NO +import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocRequestFields.RQT_VERSION import ac.uk.ebi.biostd.persistence.doc.integration.MongoDbReposConfig +import ac.uk.ebi.biostd.persistence.doc.model.CollectionsNames.RQT_ARCH_COL +import ac.uk.ebi.biostd.persistence.doc.model.CollectionsNames.RQT_FILE_ARCH_COL import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequest +import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequestFile import com.mongodb.BasicDBObject import ebi.ac.uk.db.MINIMUM_RUNNING_TIME import ebi.ac.uk.db.MONGO_VERSION @@ -10,6 +16,7 @@ import ebi.ac.uk.dsl.json.jsonObj import ebi.ac.uk.model.RequestStatus import ebi.ac.uk.model.RequestStatus.REQUESTED import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat @@ -20,6 +27,9 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.mongodb.core.ReactiveMongoTemplate +import org.springframework.data.mongodb.core.query.Criteria.where +import org.springframework.data.mongodb.core.query.Query import org.springframework.test.context.DynamicPropertyRegistry import org.springframework.test.context.DynamicPropertySource import org.springframework.test.context.junit.jupiter.SpringExtension @@ -37,6 +47,8 @@ import java.time.temporal.ChronoUnit @SpringBootTest(classes = [MongoDbReposConfig::class]) class SubmissionRequestDocDataRepositoryTest( @Autowired val testInstance: SubmissionRequestDocDataRepository, + @Autowired val filesRepository: SubmissionRequestFilesDocDataRepository, + @Autowired val template: ReactiveMongoTemplate, ) { @AfterEach fun afterEach() = @@ -44,6 +56,67 @@ class SubmissionRequestDocDataRepositoryTest( testInstance.deleteAll() } + @Test + fun archiveRequest() = + runTest { + val request = + DocSubmissionRequest( + id = ObjectId(), + accNo = "abc-123", + version = 2, + status = RequestStatus.CLEANED, + draftKey = "temp-123", + notifyTo = "user@test.org", + submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0" }.toString()), + totalFiles = 5, + deprecatedFiles = 10, + deprecatedPageTab = 3, + conflictingFiles = 12, + conflictingPageTab = 8, + reusedFiles = 5, + currentIndex = 6, + modificationTime = Instant.now().truncatedTo(ChronoUnit.MILLIS), + previousVersion = 1, + statusChanges = emptyList(), + ) + val rqtF1 = + DocSubmissionRequestFile( + id = ObjectId(), + accNo = "abc-123", + version = 2, + path = "file-path", + index = 1, + status = RequestFileStatus.LOADED, + previousSubFile = false, + file = BasicDBObject("property", "value"), + ) + val rqtF2 = + DocSubmissionRequestFile( + id = ObjectId(), + accNo = "abc-123", + version = 2, + path = "file-path-2", + index = 2, + status = RequestFileStatus.CLEANED, + previousSubFile = false, + file = BasicDBObject("property", "value-2"), + ) + + filesRepository.save(rqtF1) + filesRepository.save(rqtF2) + testInstance.saveRequest(request) + + val result = testInstance.archiveRequest("abc-123", 2) + assertThat(result).isEqualTo(2) + + val query = Query().addCriteria(where(RQT_ACC_NO).`is`("abc-123").andOperator(where(RQT_VERSION).`is`(2))) + val files = template.find(query, DocSubmissionRequestFile::class.java, RQT_FILE_ARCH_COL).asFlow().toList() + assertThat(files).containsExactlyInAnyOrder(rqtF1, rqtF2) + + val requests = template.find(query, DocSubmissionRequest::class.java, RQT_ARCH_COL).asFlow().toList() + assertThat(requests).containsExactly(request) + } + @Test fun saveRequestWhenNew() = runTest { diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceServiceTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceServiceTest.kt index 59c725609..94d61fef1 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceServiceTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestFilesMongoPersistenceServiceTest.kt @@ -5,7 +5,7 @@ import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.INDEXED import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.LOADED import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestDocDataRepository -import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestFilesRepository +import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestFilesDocDataRepository import ac.uk.ebi.biostd.persistence.doc.integration.MongoDbReposConfig import ebi.ac.uk.db.MINIMUM_RUNNING_TIME import ebi.ac.uk.db.MONGO_VERSION @@ -43,7 +43,7 @@ class SubmissionRequestFilesMongoPersistenceServiceTest( private val tempFolder: TemporaryFolder, @Autowired private val extSerializationService: ExtSerializationService, @Autowired private val requestRepository: SubmissionRequestDocDataRepository, - @Autowired private val requestFilesRepository: SubmissionRequestFilesRepository, + @Autowired private val requestFilesRepository: SubmissionRequestFilesDocDataRepository, ) { private val testInstance = SubmissionRequestFilesMongoPersistenceService( diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt index d51870c64..4f1fae394 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt @@ -1,15 +1,17 @@ package ac.uk.ebi.biostd.persistence.doc.service +import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.INDEXED import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.LOADED import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestDocDataRepository -import ac.uk.ebi.biostd.persistence.doc.db.reactive.repositories.SubmissionRequestFilesRepository +import ac.uk.ebi.biostd.persistence.doc.db.data.SubmissionRequestFilesDocDataRepository import ac.uk.ebi.biostd.persistence.doc.integration.LockConfig import ac.uk.ebi.biostd.persistence.doc.integration.MongoDbReposConfig import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequest +import ac.uk.ebi.biostd.persistence.doc.model.DocSubmissionRequestFile import ac.uk.ebi.biostd.persistence.doc.test.doc.ext.fullExtSubmission import com.mongodb.BasicDBObject import ebi.ac.uk.asserts.assertThrows @@ -48,6 +50,7 @@ import org.testcontainers.utility.DockerImageName import uk.ac.ebi.extended.serialization.service.ExtSerializationService import java.time.Duration.ofSeconds import java.time.Instant +import java.time.temporal.ChronoUnit @ExtendWith(MockKExtension::class, SpringExtension::class, TemporaryFolderExtension::class) @Testcontainers @@ -55,11 +58,16 @@ import java.time.Instant class SubmissionRequestMongoPersistenceServiceTest( private val tempFolder: TemporaryFolder, @Autowired private val requestRepository: SubmissionRequestDocDataRepository, - @Autowired private val requestFilesRepository: SubmissionRequestFilesRepository, + @Autowired private val requestFilesRepository: SubmissionRequestFilesDocDataRepository, @Autowired private val lockService: DistributedLockService, ) { private val testInstance = - SubmissionRequestMongoPersistenceService(ExtSerializationService(), requestRepository, lockService) + SubmissionRequestMongoPersistenceService( + ExtSerializationService(), + requestRepository, + requestFilesRepository, + lockService, + ) @AfterEach fun afterEach() = @@ -145,6 +153,50 @@ class SubmissionRequestMongoPersistenceServiceTest( } } + @Test + fun archiveRequest() = + runTest { + val request = + DocSubmissionRequest( + id = ObjectId(), + accNo = "abc-123", + version = 2, + status = RequestStatus.PROCESSED, + draftKey = "temp-123", + notifyTo = "user@test.org", + submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0" }.toString()), + totalFiles = 5, + deprecatedFiles = 10, + deprecatedPageTab = 3, + conflictingFiles = 12, + conflictingPageTab = 8, + reusedFiles = 5, + currentIndex = 6, + modificationTime = Instant.now().truncatedTo(ChronoUnit.MILLIS), + previousVersion = 1, + statusChanges = emptyList(), + ) + val rqtF1 = + DocSubmissionRequestFile( + id = ObjectId(), + accNo = "abc-123", + version = 2, + path = "file-path", + index = 1, + status = RequestFileStatus.LOADED, + previousSubFile = false, + file = BasicDBObject("property", "value"), + ) + + requestRepository.saveRequest(request) + requestFilesRepository.save(rqtF1) + + testInstance.archiveRequest("abc-123", 2) + + assertThat(requestRepository.findByAccNo("abc-123").toList()).isEmpty() + assertThat(requestFilesRepository.countByAccNoAndVersion("abc-123", 2)).isZero() + } + @Test fun getProcessingRequests() = runTest { diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionRequestService.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionRequestService.kt index 90353b823..9828890d1 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionRequestService.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionRequestService.kt @@ -9,7 +9,12 @@ class SubmissionRequestService( suspend fun getSubmissionRequest( accNo: String, version: Int, - ): SubmissionRequest { - return requestPersistenceService.getSubmissionRequest(accNo, version) + ): SubmissionRequest = requestPersistenceService.getSubmissionRequest(accNo, version) + + suspend fun archiveRequest( + accNo: String, + version: Int, + ) { + requestPersistenceService.archiveRequest(accNo, version) } } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionRequestResource.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionRequestResource.kt index cf2c6c4b8..180a50a38 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionRequestResource.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/web/resources/SubmissionRequestResource.kt @@ -6,6 +6,7 @@ import ebi.ac.uk.model.RequestStatus 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.ResponseBody import org.springframework.web.bind.annotation.RestController @@ -21,16 +22,21 @@ class SubmissionRequestResource( suspend fun getSubmissionRequest( @PathVariable accNo: String, @PathVariable version: Int, - ): SubmissionRequest { - return submissionRequestService.getSubmissionRequest(accNo, version) - } + ): SubmissionRequest = submissionRequestService.getSubmissionRequest(accNo, version) @GetMapping("/{accNo}/{version}/status") @ResponseBody suspend fun getSubmissionRequestStatus( @PathVariable accNo: String, @PathVariable version: Int, - ): RequestStatus { - return getSubmissionRequest(accNo, version).status + ): RequestStatus = getSubmissionRequest(accNo, version).status + + @PostMapping("/{accNo}/{version}/archive") + @ResponseBody + suspend fun archiveSubmissionRequest( + @PathVariable accNo: String, + @PathVariable version: Int, + ) { + submissionRequestService.archiveRequest(accNo, version) } }