Skip to content

Commit

Permalink
feat(backend, website): Use version comments field for revocations as…
Browse files Browse the repository at this point in the history
… well. (#2352)

* Rename version_comment metadata field versionComment for internal consistency.

* Add a versionComment field to the revoke endpoint, make sure versionComment is added to get-released-data output.

* Add DB schema updates as new flyway version.

* Add revocation comment to backend tests

* Add comment option to revoke button

* Add version comments to revocationentrydatatable and not just preview.
  • Loading branch information
anna-parker authored Aug 19, 2024
1 parent d168fe0 commit a9fa920
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 41 deletions.
11 changes: 11 additions & 0 deletions backend/src/main/kotlin/org/loculus/backend/api/SubmissionTypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ data class AccessionVersionsFilterWithDeletionScope(
val scope: DeleteSequenceScope,
)

data class AccessionsToRevokeWithComment(
@Schema(
description = "List of accessions to revoke.",
)
val accessions: List<Accession>,
@Schema(
description = "Reason for revocation or other details",
)
val versionComment: String? = null,
)

enum class ApproveDataScope {
ALL,
WITHOUT_WARNINGS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import org.jetbrains.exposed.sql.transactions.transaction
import org.loculus.backend.api.AccessionVersion
import org.loculus.backend.api.AccessionVersionsFilterWithApprovalScope
import org.loculus.backend.api.AccessionVersionsFilterWithDeletionScope
import org.loculus.backend.api.Accessions
import org.loculus.backend.api.AccessionsToRevokeWithComment
import org.loculus.backend.api.CompressionFormat
import org.loculus.backend.api.DataUseTerms
import org.loculus.backend.api.DataUseTermsType
Expand Down Expand Up @@ -397,9 +397,10 @@ class SubmissionController(
fun revoke(
@PathVariable @Valid
organism: Organism,
@RequestBody body: Accessions,
@RequestBody body: AccessionsToRevokeWithComment,
@HiddenParam authenticatedUser: AuthenticatedUser,
): List<SubmissionIdMapping> = submissionDatabaseService.revoke(body.accessions, authenticatedUser, organism)
): List<SubmissionIdMapping> =
submissionDatabaseService.revoke(body.accessions, authenticatedUser, organism, body.versionComment)

@Operation(description = DELETE_SEQUENCES_DESCRIPTION)
@ResponseStatus(HttpStatus.OK)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ class ReleasedDataModel(
("releasedDate" to TextNode(rawProcessedData.releasedAtTimestamp.toUtcDateString())) +
("versionStatus" to TextNode(siloVersionStatus.name)) +
("dataUseTerms" to TextNode(currentDataUseTerms.type.name)) +
("dataUseTermsRestrictedUntil" to restrictedDataUseTermsUntil)
("dataUseTermsRestrictedUntil" to restrictedDataUseTermsUntil) +
("versionComment" to TextNode(rawProcessedData.versionComment))

if (backendConfig.dataUseTermsUrls != null) {
val url = if (rawProcessedData.dataUseTerms == DataUseTerms.Open) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ object SequenceEntriesTable : Table(SEQUENCE_ENTRIES_TABLE_NAME) {

val accessionColumn = varchar("accession", 255)
val versionColumn = long("version")
val versionCommentColumn = varchar("version_comment", 255).nullable()
val organismColumn = varchar("organism", 255)
val submissionIdColumn = varchar("submission_id", 255)
val submitterColumn = varchar("submitter", 255)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ object SequenceEntriesView : Table(SEQUENCE_ENTRIES_VIEW_NAME) {
val releasedAtTimestampColumn = datetime("released_at").nullable()
val statusColumn = varchar("status", 255)
val isRevocationColumn = bool("is_revocation").default(false)
val versionCommentColumn = varchar("version_comment", 255).nullable()
val errorsColumn = jacksonSerializableJsonb<List<PreprocessingAnnotation>>("errors").nullable()
val warningsColumn = jacksonSerializableJsonb<List<PreprocessingAnnotation>>("warnings").nullable()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.jetbrains.exposed.sql.not
import org.jetbrains.exposed.sql.notExists
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.statements.StatementType
import org.jetbrains.exposed.sql.stringParam
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import org.loculus.backend.api.AccessionVersion
Expand Down Expand Up @@ -538,6 +539,7 @@ class SubmissionDatabaseService(
SequenceEntriesView.accessionColumn,
SequenceEntriesView.versionColumn,
SequenceEntriesView.isRevocationColumn,
SequenceEntriesView.versionCommentColumn,
SequenceEntriesView.jointDataColumn,
SequenceEntriesView.submitterColumn,
SequenceEntriesView.groupIdColumn,
Expand Down Expand Up @@ -577,6 +579,7 @@ class SubmissionDatabaseService(
DataUseTermsType.fromString(it[DataUseTermsTable.dataUseTermsTypeColumn]),
it[DataUseTermsTable.restrictedUntilColumn],
),
versionComment = it[SequenceEntriesView.versionCommentColumn],
)
}

Expand Down Expand Up @@ -673,6 +676,7 @@ class SubmissionDatabaseService(
accessions: List<Accession>,
authenticatedUser: AuthenticatedUser,
organism: Organism,
versionComment: String?,
): List<SubmissionIdMapping> {
log.info { "revoking ${accessions.size} sequences" }

Expand All @@ -682,30 +686,35 @@ class SubmissionDatabaseService(
.andThatSequenceEntriesAreInStates(listOf(Status.APPROVED_FOR_RELEASE))
.andThatOrganismIs(organism)
}

val now = Clock.System.now().toLocalDateTime(TimeZone.UTC)

SequenceEntriesTable.insert(
SequenceEntriesTable
.select(
SequenceEntriesTable.accessionColumn,
SequenceEntriesTable.versionColumn.plus(1),
SequenceEntriesTable.submissionIdColumn,
SequenceEntriesTable.submitterColumn,
SequenceEntriesTable.groupIdColumn,
dateTimeParam(now),
booleanParam(true),
SequenceEntriesTable.organismColumn,
)
.where {
(SequenceEntriesTable.accessionColumn inList accessions) and
SequenceEntriesTable.isMaxVersion
SequenceEntriesTable.select(
SequenceEntriesTable.accessionColumn, SequenceEntriesTable.versionColumn.plus(1),
when (versionComment) {
null -> Op.nullOp()
else -> stringParam(versionComment)
},
SequenceEntriesTable.submissionIdColumn,
SequenceEntriesTable.submitterColumn,
SequenceEntriesTable.groupIdColumn,
dateTimeParam(
now,
),
booleanParam(true), SequenceEntriesTable.organismColumn,
).where {
(
SequenceEntriesTable.accessionColumn inList
accessions
) and
SequenceEntriesTable.isMaxVersion
},
columns = listOf(
SequenceEntriesTable.accessionColumn,
SequenceEntriesTable.versionColumn,
SequenceEntriesTable.versionCommentColumn,
SequenceEntriesTable.submissionIdColumn,
SequenceEntriesTable.submitterColumn,
SequenceEntriesTable.groupIdColumn,
SequenceEntriesTable.submitterColumn, SequenceEntriesTable.groupIdColumn,
SequenceEntriesTable.submittedAtTimestampColumn,
SequenceEntriesTable.isRevocationColumn,
SequenceEntriesTable.organismColumn,
Expand Down Expand Up @@ -1017,6 +1026,7 @@ data class RawProcessedData(
override val accession: Accession,
override val version: Version,
val isRevocation: Boolean,
val versionComment: String?,
val submitter: String,
val groupId: Int,
val groupName: String,
Expand Down
30 changes: 30 additions & 0 deletions backend/src/main/resources/db/migration/V1.1__add_field.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
alter table sequence_entries add column version_comment text;

drop view if exists sequence_entries_view;

create view sequence_entries_view as
select
se.*,
sepd.started_processing_at,
sepd.finished_processing_at,
sepd.processed_data as processed_data,
sepd.processed_data || em.joint_metadata as joint_metadata,
sepd.errors,
sepd.warnings,
case
when se.released_at is not null then 'APPROVED_FOR_RELEASE'
when se.is_revocation then 'AWAITING_APPROVAL'
when sepd.processing_status = 'IN_PROCESSING' then 'IN_PROCESSING'
when sepd.processing_status = 'HAS_ERRORS' then 'HAS_ERRORS'
when sepd.processing_status = 'FINISHED' then 'AWAITING_APPROVAL'
else 'RECEIVED'
end as status
from
sequence_entries se
left join sequence_entries_preprocessed_data sepd on
se.accession = sepd.accession
and se.version = sepd.version
and sepd.pipeline_version = (select version from current_processing_pipeline)
left join external_metadata_view em on
se.accession = em.accession
and se.version = em.version;
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class GetReleasedDataEndpointTest(
"releasedDate" to TextNode(Clock.System.now().toLocalDateTime(TimeZone.UTC).date.toString()),
"submittedDate" to TextNode(Clock.System.now().toLocalDateTime(TimeZone.UTC).date.toString()),
"dataUseTermsRestrictedUntil" to NullNode.getInstance(),
"versionComment" to NullNode.getInstance(),
"booleanColumn" to BooleanNode.TRUE,
)

Expand Down Expand Up @@ -214,10 +215,17 @@ class GetReleasedDataEndpointTest(
value,
`is`(TextNode(Clock.System.now().toLocalDateTime(TimeZone.UTC).date.toString())),
)

"releasedDate" -> assertThat(
value,
`is`(TextNode(Clock.System.now().toLocalDateTime(TimeZone.UTC).date.toString())),
)

"versionComment" -> assertThat(
value,
`is`(TextNode("This is a test revocation")),
)

else -> assertThat("value for $key", value, `is`(NullNode.instance))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,17 @@ class SubmissionControllerClient(private val mockMvc: MockMvc, private val objec
listOfSequenceEntriesToRevoke: List<Accession>,
organism: String = DEFAULT_ORGANISM,
jwt: String? = jwtForDefaultUser,
versionComment: String? = null,
): ResultActions = mockMvc.perform(
post(addOrganismToPath("/revoke", organism = organism))
.contentType(MediaType.APPLICATION_JSON)
.content("""{"accessions":${objectMapper.writeValueAsString(listOfSequenceEntriesToRevoke)}}""")
.content(
"""{"accessions":${
objectMapper.writeValueAsString(
listOfSequenceEntriesToRevoke,
)
}, "versionComment":${objectMapper.writeValueAsString(versionComment)}}""",
)
.withAuth(jwt),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,14 @@ class SubmissionConvenienceClient(

fun prepareRevokedSequenceEntries(organism: String = DEFAULT_ORGANISM): List<AccessionVersionInterface> {
val accessionVersions = prepareDataTo(Status.APPROVED_FOR_RELEASE, organism = organism)
val revocationVersions = revokeSequenceEntries(accessionVersions.map { it.accession }, organism = organism)
val revocationVersions =
revokeSequenceEntries(
accessionVersions.map {
it.accession
},
organism = organism,
versionComment = "This is a test revocation",
)
return approveProcessedSequenceEntries(revocationVersions, organism = organism)
}

Expand Down Expand Up @@ -323,11 +330,13 @@ class SubmissionConvenienceClient(
listOfAccessionsToRevoke: List<Accession>,
organism: String = DEFAULT_ORGANISM,
username: String = DEFAULT_USER_NAME,
versionComment: String? = null,
): List<SubmissionIdMapping> = deserializeJsonResponse(
client.revokeSequenceEntries(
listOfAccessionsToRevoke,
organism = organism,
jwt = generateJwtFor(username),
versionComment = versionComment,
),
)

Expand Down
2 changes: 1 addition & 1 deletion kubernetes/loculus/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ defaultOrganismConfig: &defaultOrganismConfig
rangeSearch: true
preprocessing:
inputs: {input: nextclade.coverage}
- name: version_comment
- name: versionComment
displayName: Version Comment
header: Submission details
website: &website
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
RELEASED_AT_FIELD,
IS_REVOCATION_FIELD,
ACCESSION_FIELD,
VERSION_COMMENT_FIELD,
VERSION_STATUS_FIELD,
SUBMITTER_FIELD,
GROUP_NAME_FIELD,
Expand All @@ -31,6 +32,7 @@ const relevantFieldsForRevocationVersions = [
ACCESSION_FIELD,
IS_REVOCATION_FIELD,
RELEASED_AT_FIELD,
VERSION_COMMENT_FIELD,
VERSION_STATUS_FIELD,
SUBMITTED_AT_FIELD,
SUBMITTER_FIELD,
Expand Down
Loading

0 comments on commit a9fa920

Please sign in to comment.