diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt index 74dff70083d075cca4827a6ef246a94810b66db0..a7170706b799bb436a7fd41250986f3aec8f8414 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModel.kt @@ -21,6 +21,7 @@ import de.rki.coronawarnapp.contactdiary.ui.overview.adapter.day.riskevent.RiskE import de.rki.coronawarnapp.contactdiary.ui.overview.adapter.subheader.OverviewSubHeaderItem import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository +import de.rki.coronawarnapp.presencetracing.checkins.common.locationName import de.rki.coronawarnapp.presencetracing.risk.TraceLocationCheckInRisk import de.rki.coronawarnapp.risk.RiskState import de.rki.coronawarnapp.risk.result.ExposureWindowDayRisk @@ -147,13 +148,8 @@ class ContactDiaryOverviewViewModel @AssistedInject constructor( val riskEventItem = traceLocationCheckInRisksForDate .mapNotNull { - val locationVisit = visitsForDate.find { visit -> visit.checkInID == it.checkInId } - val checkIn = checkInList.find { checkIn -> checkIn.id == it.checkInId } - - return@mapNotNull when (locationVisit != null && checkIn != null) { - true -> RiskEventDataHolder(it, locationVisit, checkIn) - else -> null - } + val checkIn = checkInList.find { checkIn -> checkIn.id == it.checkInId } ?: return@mapNotNull null + RiskEventDataHolder(it, checkIn) }.toRiskEventItem() DayOverviewItem( @@ -209,7 +205,6 @@ class ContactDiaryOverviewViewModel @AssistedInject constructor( private data class RiskEventDataHolder( val traceLocationCheckInRisk: TraceLocationCheckInRisk, - val locationVisit: ContactDiaryLocationVisit, val checkIn: CheckIn ) @@ -234,7 +229,8 @@ class ContactDiaryOverviewViewModel @AssistedInject constructor( } val events = map { data -> - val name = data.locationVisit.contactDiaryLocation.locationName + val checkIn = data.checkIn + val name = checkIn.locationName val bulletPointColor: Int var riskInfoAddition: Int? @@ -252,7 +248,7 @@ class ContactDiaryOverviewViewModel @AssistedInject constructor( if (size < 2) riskInfoAddition = null - val description = data.checkIn.description + val description = checkIn.description RiskEventItem.Event( name = name, @@ -262,8 +258,6 @@ class ContactDiaryOverviewViewModel @AssistedInject constructor( ) } - if (events.isEmpty()) return null - return RiskEventItem( title = title, body = body, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreator.kt index e770f6db91734c0c3e171d327ca43563f082681b..deef3a5c16cfbdb77844280e949dbd97e3be972c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreator.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreator.kt @@ -8,13 +8,12 @@ import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryLocation import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryLocationVisit import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import de.rki.coronawarnapp.presencetracing.checkins.CheckIn +import de.rki.coronawarnapp.presencetracing.checkins.common.locationName import de.rki.coronawarnapp.presencetracing.checkins.split.splitByMidnightUTC import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc -import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone import kotlinx.coroutines.flow.first import org.joda.time.Duration import org.joda.time.Seconds -import org.joda.time.format.DateTimeFormat import timber.log.Timber import javax.inject.Inject import kotlin.math.roundToLong @@ -47,7 +46,7 @@ class ContactJournalCheckInEntryCreator @Inject constructor( private suspend fun CheckIn.createLocationEntry(): ContactDiaryLocation { Timber.d("Creating new contact diary location from %s", this) val location = DefaultContactDiaryLocation( - locationName = toLocationName(), + locationName = locationName, traceLocationID = traceLocationId ) @@ -56,21 +55,6 @@ class ContactJournalCheckInEntryCreator @Inject constructor( .also { Timber.d("Created %s and added it to contact journal db", it) } } - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - fun CheckIn.toLocationName(): String { - val nameParts = mutableListOf(description, address) - - if (traceLocationStart != null && traceLocationEnd != null) { - if (traceLocationStart.millis > 0 && traceLocationEnd.millis > 0) { - val formattedStartDate = traceLocationStart.toUserTimeZone().toString(DateTimeFormat.shortDateTime()) - val formattedEndDate = traceLocationEnd.toUserTimeZone().toString(DateTimeFormat.shortDateTime()) - nameParts.add("$formattedStartDate - $formattedEndDate") - } - } - - return nameParts.joinToString(separator = ", ") - } - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) fun CheckIn.toLocationVisit(location: ContactDiaryLocation): ContactDiaryLocationVisit { // Duration column is set by calculating the time difference in minutes between Check-in StartDate diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/common/CheckInExtension.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/common/CheckInExtension.kt new file mode 100644 index 0000000000000000000000000000000000000000..4d39591c739eab7dbed59a92d19b78f87ef1eb60 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/checkins/common/CheckInExtension.kt @@ -0,0 +1,20 @@ +package de.rki.coronawarnapp.presencetracing.checkins.common + +import de.rki.coronawarnapp.presencetracing.checkins.CheckIn +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone +import org.joda.time.format.DateTimeFormat + +val CheckIn.locationName: String + get() { + val nameParts = mutableListOf(description, address) + + if (traceLocationStart != null && traceLocationEnd != null) { + if (traceLocationStart.millis > 0 && traceLocationEnd.millis > 0) { + val formattedStartDate = traceLocationStart.toUserTimeZone().toString(DateTimeFormat.shortDateTime()) + val formattedEndDate = traceLocationEnd.toUserTimeZone().toString(DateTimeFormat.shortDateTime()) + nameParts.add("$formattedStartDate - $formattedEndDate") + } + } + + return nameParts.joinToString(separator = ", ") + } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModelTest.kt index f17d6c08cf076ebf3b5bd7e82a80c89a1d9ba8b9..86f776afc70b37dec997498d0e3d1c3f84eec90f 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/ui/overview/ContactDiaryOverviewViewModelTest.kt @@ -17,6 +17,7 @@ import de.rki.coronawarnapp.contactdiary.util.ContactDiaryData import de.rki.coronawarnapp.contactdiary.util.mockStringsForContactDiaryExporterTests import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository +import de.rki.coronawarnapp.presencetracing.checkins.common.locationName import de.rki.coronawarnapp.presencetracing.risk.TraceLocationCheckInRisk import de.rki.coronawarnapp.risk.RiskState import de.rki.coronawarnapp.risk.result.ExposureWindowDayRisk @@ -81,16 +82,34 @@ open class ContactDiaryOverviewViewModelTest { private val personEncounter = DefaultContactDiaryPersonEncounter(125, date, person) private val locationVisit = DefaultContactDiaryLocationVisit(126, date, location) + private val checkInLow = mockk<CheckIn>().apply { + every { id } returns 147 + every { traceLocationId } returns "12ab-34cd-56ef-78gh-456".decodeBase64()!! + every { description } returns "Jahrestreffen der deutschen SAP Anwendergruppe" + every { address } returns "Hauptstr 3, 69115 Heidelberg" + every { traceLocationStart } returns null + every { traceLocationEnd } returns null + } + + private val checkInHigh = mockk<CheckIn>().apply { + every { id } returns 148 + every { traceLocationId } returns "12ab-34cd-56ef-78gh-457".decodeBase64()!! + every { description } returns "Kiosk" + every { address } returns "Hauptstr 4, 69115 Heidelberg" + every { traceLocationStart } returns null + every { traceLocationEnd } returns null + } + private val locationEventLowRisk = DefaultContactDiaryLocation( locationId = 456, - locationName = "Jahrestreffen der deutschen SAP Anwendergruppe", - traceLocationID = "12ab-34cd-56ef-78gh-456".decodeBase64() + locationName = checkInLow.locationName, + traceLocationID = checkInLow.traceLocationId ) private val locationEventHighRisk = DefaultContactDiaryLocation( locationId = 457, - locationName = "Kiosk", - traceLocationID = "12ab-34cd-56ef-78gh-457".decodeBase64() + locationName = checkInHigh.locationName, + traceLocationID = checkInHigh.traceLocationId ) private val locationEventLowRiskVisit = DefaultContactDiaryLocationVisit( @@ -108,27 +127,17 @@ open class ContactDiaryOverviewViewModelTest { ) private val traceLocationCheckInRiskLow = object : TraceLocationCheckInRisk { - override val checkInId: Long = 147 + override val checkInId: Long = checkInLow.id override val localDateUtc: LocalDate = date override val riskState: RiskState = RiskState.LOW_RISK } private val traceLocationCheckInRiskHigh = object : TraceLocationCheckInRisk { - override val checkInId: Long = 148 + override val checkInId: Long = checkInHigh.id override val localDateUtc: LocalDate = date override val riskState: RiskState = RiskState.INCREASED_RISK } - private val checkInLow = mockk<CheckIn>().apply { - every { id } returns traceLocationCheckInRiskLow.checkInId - every { description } returns "I can make orange rhyme with banana... Bornana" - } - - private val checkInHigh = mockk<CheckIn>().apply { - every { id } returns traceLocationCheckInRiskHigh.checkInId - every { description } returns "I'm the bad guy cause I caused the high risk" - } - private val aggregatedRiskPerDateResultLowRisk = ExposureWindowDayRisk( dateMillisSinceEpoch = dateMillis, riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.LOW, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreatorTest.kt index d66bb45ec8852bed62d248b9d19a77d3ee5c4c09..000eebe6ce6d0be416bfba37367ad391df786f34 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreatorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/checkins/checkout/ContactJournalCheckInEntryCreatorTest.kt @@ -4,8 +4,8 @@ import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryLocation import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryLocationVisit import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import de.rki.coronawarnapp.presencetracing.checkins.CheckIn +import de.rki.coronawarnapp.presencetracing.checkins.common.locationName import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc -import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.coEvery @@ -21,7 +21,6 @@ import okio.ByteString.Companion.encode import org.joda.time.Days import org.joda.time.Instant import org.joda.time.Minutes -import org.joda.time.format.DateTimeFormat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest @@ -50,7 +49,7 @@ class ContactJournalCheckInEntryCreatorTest : BaseTest() { private val testLocation = DefaultContactDiaryLocation( locationId = 123L, - locationName = "${testCheckIn.description}, ${testCheckIn.address}, ${testCheckIn.traceLocationStart?.toPrettyDate()} - ${testCheckIn.traceLocationEnd?.toPrettyDate()}", + locationName = testCheckIn.locationName, traceLocationID = testCheckIn.traceLocationId ) @@ -62,8 +61,6 @@ class ContactJournalCheckInEntryCreatorTest : BaseTest() { duration = Minutes.minutes(60).toStandardDuration() ) - private fun Instant.toPrettyDate(): String = toUserTimeZone().toString(DateTimeFormat.shortDateTime()) - @BeforeEach fun setup() { MockKAnnotations.init(this) @@ -111,28 +108,6 @@ class ContactJournalCheckInEntryCreatorTest : BaseTest() { } } - @Test - fun `Location name concatenates description, address and if both are set trace location start and end date`() { - val testCheckInNoTraceLocationStartDate = testCheckIn.copy(traceLocationStart = null) - val testCheckInNoTraceLocationEndDate = testCheckIn.copy(traceLocationEnd = null) - val testCheckInNoTraceLocationStartAndEndDate = - testCheckIn.copy(traceLocationStart = null, traceLocationEnd = null) - - createInstance().apply { - testCheckIn.validateLocationName(testCheckIn.toLocationName()) - testCheckInNoTraceLocationStartDate.validateLocationName(testCheckInNoTraceLocationStartDate.toLocationName()) - testCheckInNoTraceLocationEndDate.validateLocationName(testCheckInNoTraceLocationEndDate.toLocationName()) - testCheckInNoTraceLocationStartAndEndDate.validateLocationName(testCheckInNoTraceLocationStartAndEndDate.toLocationName()) - } - } - - private fun CheckIn.validateLocationName(nameToValidate: String) { - nameToValidate shouldBe when (traceLocationStart != null && traceLocationEnd != null) { - true -> "$description, $address, ${traceLocationStart?.toPrettyDate()} - ${traceLocationEnd?.toPrettyDate()}" - else -> "$description, $address" - } - } - @Test fun `CheckIn to ContactDiaryLocationVisit is correct`() { createInstance().apply { diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/checkins/common/CheckInExtensionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/checkins/common/CheckInExtensionTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..8851229725e68370b9e06852532580e5431a8df5 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/checkins/common/CheckInExtensionTest.kt @@ -0,0 +1,54 @@ +package de.rki.coronawarnapp.presencetracing.checkins.common + +import de.rki.coronawarnapp.presencetracing.checkins.CheckIn +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toUserTimeZone +import io.kotest.matchers.shouldBe +import okio.ByteString.Companion.decodeBase64 +import okio.ByteString.Companion.encode +import org.joda.time.Instant +import org.joda.time.format.DateTimeFormat +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class CheckInExtensionTest : BaseTest() { + + private val testCheckIn = CheckIn( + id = 42L, + traceLocationId = "traceLocationId1".decodeBase64()!!, + version = 1, + type = 1, + description = "Restaurant", + address = "Around the corner", + traceLocationStart = Instant.parse("2021-03-04T22:00+01:00"), + traceLocationEnd = Instant.parse("2021-03-04T23:00+01:00"), + defaultCheckInLengthInMinutes = null, + cryptographicSeed = "cryptographicSeed".encode(), + cnPublicKey = "cnPublicKey", + checkInStart = Instant.parse("2021-03-04T22:00+01:00"), + checkInEnd = Instant.parse("2021-03-04T23:00+01:00"), + completed = false, + createJournalEntry = true + ) + + private fun Instant.toPrettyDate(): String = toUserTimeZone().toString(DateTimeFormat.shortDateTime()) + + @Test + fun `Location name concatenates description, address and if both are set trace location start and end date`() { + val testCheckInNoTraceLocationStartDate = testCheckIn.copy(traceLocationStart = null) + val testCheckInNoTraceLocationEndDate = testCheckIn.copy(traceLocationEnd = null) + val testCheckInNoTraceLocationStartAndEndDate = + testCheckIn.copy(traceLocationStart = null, traceLocationEnd = null) + + testCheckIn.validateLocationName() + testCheckInNoTraceLocationStartDate.validateLocationName() + testCheckInNoTraceLocationEndDate.validateLocationName() + testCheckInNoTraceLocationStartAndEndDate.validateLocationName() + } + + private fun CheckIn.validateLocationName() { + locationName shouldBe when (traceLocationStart != null && traceLocationEnd != null) { + true -> "$description, $address, ${traceLocationStart?.toPrettyDate()} - ${traceLocationEnd?.toPrettyDate()}" + else -> "$description, $address" + } + } +}