Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.loculus.backend.model

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.BooleanNode
import com.fasterxml.jackson.databind.node.IntNode
Expand Down Expand Up @@ -124,6 +125,7 @@ open class ReleasedDataModel(
} else {
NullNode.getInstance()
}
val dataBecameOpenAt = computeDataBecameOpenAt(rawProcessedData, currentDataUseTerms)

val earliestReleaseDate = earliestReleaseDateFinder?.calculateEarliestReleaseDate(rawProcessedData)

Expand Down Expand Up @@ -159,6 +161,7 @@ open class ReleasedDataModel(
mapOf(
"dataUseTerms" to TextNode(currentDataUseTerms.type.name),
"dataUseTermsRestrictedUntil" to restrictedDataUseTermsUntil,
"dataBecameOpenAt" to dataBecameOpenAt,
)
},
) +
Expand Down Expand Up @@ -235,6 +238,21 @@ open class ReleasedDataModel(
DataUseTerms.Open
}

private fun computeDataBecameOpenAt(
rawProcessedData: RawProcessedData,
currentDataUseTerms: DataUseTerms,
): JsonNode = when {
Comment thread
anna-parker marked this conversation as resolved.
currentDataUseTerms is DataUseTerms.Restricted -> NullNode.getInstance()

rawProcessedData.dataUseTerms is DataUseTerms.Restricted ->
TextNode(rawProcessedData.dataUseTerms.restrictedUntil.toString())

rawProcessedData.dataUseTermsChangeDate != null ->
TextNode(rawProcessedData.dataUseTermsChangeDate.toUtcDateString())

else -> NullNode.getInstance()
}

// LATEST_VERSION: This is the highest version of the sequence entry
// REVOKED: This is not the highest version of the sequence entry, and a higher version is a revocation
// REVISED: This is not the highest version of the sequence entry, and no higher version is a revocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,7 @@ class SubmissionDatabaseService(
SequenceEntriesView.pipelineVersionColumn,
DataUseTermsTable.dataUseTermsTypeColumn,
DataUseTermsTable.restrictedUntilColumn,
DataUseTermsTable.changeDateColumn,
)
.where {
SequenceEntriesView.statusIs(Status.APPROVED_FOR_RELEASE) and SequenceEntriesView.organismIs(
Expand Down Expand Up @@ -779,6 +780,7 @@ class SubmissionDatabaseService(
it[DataUseTermsTable.restrictedUntilColumn],
),
versionComment = it[SequenceEntriesView.versionCommentColumn],
dataUseTermsChangeDate = it[DataUseTermsTable.changeDateColumn],
Comment thread
anna-parker marked this conversation as resolved.
)
}

Expand Down Expand Up @@ -1533,4 +1535,5 @@ data class RawProcessedData(
val processedData: ProcessedData<GeneticSequence>,
val pipelineVersion: Long,
val dataUseTerms: DataUseTerms,
val dataUseTermsChangeDate: LocalDateTime?,
) : AccessionVersionInterface
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class GetReleasedDataEndpointTest(
"releasedDate" to TextNode(currentDate),
"submittedDate" to TextNode(currentDate),
"dataUseTermsRestrictedUntil" to NullNode.getInstance(),
"dataBecameOpenAt" to TextNode(currentDate),
"pipelineVersion" to IntNode(DEFAULT_PIPELINE_VERSION.toInt()),
)

Expand Down Expand Up @@ -346,6 +347,8 @@ class GetReleasedDataEndpointTest(

"pipelineVersion" -> assertThat(value, `is`(IntNode(DEFAULT_PIPELINE_VERSION.toInt())))

"dataBecameOpenAt" -> assertThat(value, `is`(TextNode(currentDate)))

else -> assertThat("value for $key", value, `is`(NullNode.instance))
}
}
Expand Down Expand Up @@ -545,6 +548,92 @@ class GetReleasedDataEndpointWithDataUseTermsUrlTest(
assertAccessionVersionIsOpen(accessionVersion)
}

@Test
fun `GIVEN different data use terms scenarios THEN dataBecameOpenAt is computed correctly`() {
Comment thread
anna-parker marked this conversation as resolved.
every { dateProvider.getCurrentInstant() } answers { callOriginal() }

val threeMonthsFromNow = dateMonthsFromNow(3)
val currentDate = dateProvider.getCurrentDate()

// Scenario 1: Data submitted as OPEN - dataBecameOpenAt should be the submission date
val openAccessionVersion = convenienceClient.prepareDataTo(
status = Status.APPROVED_FOR_RELEASE,
dataUseTerms = DataUseTerms.Open,
)[0]

var releasedData = getReleasedDataForAccessionVersion(openAccessionVersion)
assertThat(
"OPEN data should have dataBecameOpenAt set to submission date",
releasedData.metadata["dataBecameOpenAt"]?.textValue(),
`is`(currentDate.toString()),
)

// Scenario 2: Data submitted as RESTRICTED - dataBecameOpenAt should be null
val restrictedAccessionVersion = convenienceClient.prepareDataTo(
status = Status.APPROVED_FOR_RELEASE,
dataUseTerms = DataUseTerms.Restricted(threeMonthsFromNow),
)[0]

releasedData = getReleasedDataForAccessionVersion(restrictedAccessionVersion)
assertThat(
"RESTRICTED data should have null dataBecameOpenAt",
releasedData.metadata["dataBecameOpenAt"],
`is`(NullNode.instance),
)

// Scenario 3: Data changed from RESTRICTED to OPEN - dataBecameOpenAt should be the change date
// Fast-forward one month before changing to OPEN
val oneMonthFromNow = dateMonthsFromNow(1)
val oneMonthFromNowInstant = LocalDateTime(
date = oneMonthFromNow,
time = LocalTime.fromSecondOfDay(0),
).toInstant(DateProvider.timeZone)
every { dateProvider.getCurrentInstant() } answers { oneMonthFromNowInstant }

dataUseTermsClient.changeDataUseTerms(
newDataUseTerms = DataUseTermsChangeRequest(
accessions = listOf(restrictedAccessionVersion.accession),
newDataUseTerms = DataUseTerms.Open,
),
jwt = jwtForDefaultUser,
)

releasedData = getReleasedDataForAccessionVersion(restrictedAccessionVersion)
assertThat(
"Data changed to OPEN should have dataBecameOpenAt set to change date",
releasedData.metadata["dataBecameOpenAt"]?.textValue(),
`is`(oneMonthFromNow.toString()),
)

// Reset time for next scenario
every { dateProvider.getCurrentInstant() } answers { callOriginal() }

// Scenario 4: Expired RESTRICTED data - dataBecameOpenAt should be the restrictedUntil date
val anotherRestrictedAccessionVersion = convenienceClient.prepareDataTo(
status = Status.APPROVED_FOR_RELEASE,
dataUseTerms = DataUseTerms.Restricted(threeMonthsFromNow),
)[0]

// Fast-forward time past the restriction date
val threeMonthsAndADayFromNow = LocalDateTime(
date = threeMonthsFromNow.plus(1, DateTimeUnit.DAY),
time = LocalTime.fromSecondOfDay(0),
).toInstant(DateProvider.timeZone)
every { dateProvider.getCurrentInstant() } answers { threeMonthsAndADayFromNow }

releasedData = getReleasedDataForAccessionVersion(anotherRestrictedAccessionVersion)
assertThat(
"Expired RESTRICTED data should have dataBecameOpenAt set to restrictedUntil date",
releasedData.metadata["dataBecameOpenAt"]?.textValue(),
`is`(threeMonthsFromNow.toString()),
)
}

private fun getReleasedDataForAccessionVersion(accessionVersion: AccessionVersionInterface): ReleasedData =
submissionControllerClient.getReleasedData()
.expectNdjsonAndGetContent<ReleasedData>()
.find { it.metadata["accessionVersion"]?.textValue() == accessionVersion.displayAccessionVersion() }!!

private fun assertAccessionVersionIsOpen(accessionVersion: AccessionVersionInterface) {
assertAccessionVersionHasReleasedDataValues(
accessionVersion = accessionVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ fun row(
groupName = "foo",
dataUseTerms = DataUseTerms.Open,
pipelineVersion = 0,
dataUseTermsChangeDate = releasedAt,
)

// Notes:
Expand Down
6 changes: 6 additions & 0 deletions kubernetes/loculus/templates/_common-metadata.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ fields:
hideOnSequenceDetailsPage: true
header: Data use terms
orderOnDetailsPage: 620
- name: dataBecameOpenAt
Comment thread
anna-parker marked this conversation as resolved.
type: date
displayName: Date data became open
hideOnSequenceDetailsPage: true
header: Data use terms
orderOnDetailsPage: 625
{{- if $.Values.dataUseTerms.urls }}
- name: dataUseTermsUrl
displayName: Data use terms URL
Expand Down
Loading