diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCase.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCase.kt index da6b742589..355f117d9f 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCase.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCase.kt @@ -1,5 +1,9 @@ package com.simprints.feature.clientapi.usecases +import com.fasterxml.jackson.databind.module.SimpleModule +import com.simprints.core.domain.tokenization.TokenizableString +import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameDeserializer +import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameSerializer import com.simprints.core.tools.json.JsonHelper import com.simprints.core.tools.utils.EncodingUtils import com.simprints.infra.config.store.models.canCoSyncAllData @@ -34,7 +38,7 @@ internal class GetEnrolmentCreationEventForSubjectUseCase @Inject constructor( ?.fromSubjectToEnrolmentCreationEvent() ?: return null - return jsonHelper.toJson(CoSyncEnrolmentRecordEvents(listOf(recordCreationEvent))) + return jsonHelper.toJson(CoSyncEnrolmentRecordEvents(listOf(recordCreationEvent)), coSyncSerializationModule) } private fun Subject.fromSubjectToEnrolmentCreationEvent() = EnrolmentRecordCreationEvent( @@ -44,4 +48,11 @@ internal class GetEnrolmentCreationEventForSubjectUseCase @Inject constructor( attendantId, EnrolmentRecordCreationEvent.buildBiometricReferences(fingerprintSamples, faceSamples, encoder), ) + + companion object { + val coSyncSerializationModule = SimpleModule().apply { + addSerializer(TokenizableString::class.java, TokenizationClassNameSerializer()) + addDeserializer(TokenizableString::class.java, TokenizationClassNameDeserializer()) + } + } } diff --git a/feature/client-api/src/test/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCaseTest.kt b/feature/client-api/src/test/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCaseTest.kt index 60285cb7d4..3d0b70f208 100644 --- a/feature/client-api/src/test/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCaseTest.kt +++ b/feature/client-api/src/test/java/com/simprints/feature/clientapi/usecases/GetEnrolmentCreationEventForSubjectUseCaseTest.kt @@ -98,7 +98,7 @@ class GetEnrolmentCreationEventForSubjectUseCaseTest { val result = useCase("projectId", "subjectId") coVerify { enrolmentRecordRepository.load(any()) } - coVerify { jsonHelper.toJson(any()) } + coVerify { jsonHelper.toJson(any(), any()) } assertThat(result).isNotNull() } } diff --git a/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/commcare/CommCareIdentityDataSource.kt b/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/commcare/CommCareIdentityDataSource.kt index 6de2f533be..7fc86838cb 100644 --- a/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/commcare/CommCareIdentityDataSource.kt +++ b/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/commcare/CommCareIdentityDataSource.kt @@ -40,14 +40,6 @@ internal class CommCareIdentityDataSource @Inject constructor( @ApplicationContext private val context: Context, @DispatcherIO private val dispatcher: CoroutineDispatcher, ) : IdentityDataSource { - companion object { - const val COLUMN_CASE_ID = "case_id" - const val COLUMN_DATUM_ID = "datum_id" - const val COLUMN_VALUE = "value" - - const val ARG_CASE_ID = "caseId" - } - private fun getCaseMetadataUri(packageName: String): Uri = Uri.parse("content://$packageName.case/casedb/case") private fun getCaseDataUri(packageName: String): Uri = Uri.parse("content://$packageName.case/casedb/data") @@ -106,7 +98,9 @@ internal class CommCareIdentityDataSource @Inject constructor( if (caseMetadataCursor.moveToPosition(range.first)) { do { caseMetadataCursor.getString(caseMetadataCursor.getColumnIndexOrThrow(COLUMN_CASE_ID))?.let { caseId -> - enrolmentRecordCreationEvents.addAll(loadEnrolmentRecordCreationEvents(caseId, callerPackageName, query, project)) + enrolmentRecordCreationEvents.addAll( + loadEnrolmentRecordCreationEvents(caseId, callerPackageName, query, project), + ) onCandidateLoaded() } } while (caseMetadataCursor.moveToNext() && caseMetadataCursor.position < range.last) @@ -160,7 +154,7 @@ internal class CommCareIdentityDataSource @Inject constructor( caseId: String, callerPackageName: String, query: SubjectQuery, - project: Project + project: Project, ): List { // Access Case Data Listing for the caseId val caseDataUri = getCaseDataUri(callerPackageName).buildUpon().appendPath(caseId).build() @@ -181,15 +175,15 @@ internal class CommCareIdentityDataSource @Inject constructor( (query.subjectId != null && query.subjectId != event.payload.subjectId) || !compareImplicitTokenizedStringsUseCase( query.attendantId, - event.payload.attendantId.value, + event.payload.attendantId, TokenKeyType.AttendantId, - project + project, ) || !compareImplicitTokenizedStringsUseCase( query.moduleId, - event.payload.moduleId.value, + event.payload.moduleId, TokenKeyType.ModuleId, - project + project, ) } }.orEmpty() @@ -244,4 +238,12 @@ internal class CommCareIdentityDataSource @Inject constructor( )?.use { caseMetadataCursor -> count = caseMetadataCursor.count } count } + + companion object { + const val COLUMN_CASE_ID = "case_id" + const val COLUMN_DATUM_ID = "datum_id" + const val COLUMN_VALUE = "value" + + const val ARG_CASE_ID = "caseId" + } } diff --git a/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCase.kt b/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCase.kt index 6ea6618c30..4291bf7412 100644 --- a/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCase.kt +++ b/infra/enrolment-records-store/src/main/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCase.kt @@ -9,7 +9,7 @@ import com.simprints.infra.config.store.tokenization.TokenizationProcessor import javax.inject.Inject /** - * Use case that checks two plain strings values but considers that the tokenization state of one of the values + * Use case that checks two TokenizableStrings but considers that the tokenization state of one of the values * might differ from another. In this case this use tries to bring both strings to the same tokenization state * and compare their values. * Example: @@ -17,13 +17,16 @@ import javax.inject.Inject * s2 = 'AWcDe/==seF1LkcF4' - tokenized value (result of tokenizing the 'abc' value) * * Even though plain string values are different, they represent the same entity. s1 is going to be encrypted and compared to the s2. + * + * Given the implementation of TokenizationClassNameDeserializer - if a value is TokenizableString.Tokenized, we can be sure that it is tokenized. + * Only deserialized TokenizableString.Raw values have uncertain tokenization state. */ class CompareImplicitTokenizedStringsUseCase @Inject constructor( private val tokenizationProcessor: TokenizationProcessor, ) { operator fun invoke( s1: TokenizableString?, - s2: String, + s2: TokenizableString, tokenKeyType: TokenKeyType, project: Project, ): Boolean = when { @@ -37,33 +40,23 @@ class CompareImplicitTokenizedStringsUseCase @Inject constructor( project: Project, ): TokenizableString = when (s) { is TokenizableString.Tokenized -> s - is TokenizableString.Raw -> tokenizationProcessor.encrypt( - decrypted = s, - tokenKeyType = tokenKeyType, - project = project, - ) - } - - private fun ensureTokenized( - s: String, - tokenKeyType: TokenKeyType, - project: Project, - ): TokenizableString { - val isAlreadyTokenized = tokenizationProcessor.decrypt( - encrypted = s.asTokenizableEncrypted(), - tokenKeyType = tokenKeyType, - project = project, - logError = false, - ) is TokenizableString.Raw - - return if (isAlreadyTokenized) { - s.asTokenizableEncrypted() - } else { - tokenizationProcessor.encrypt( - decrypted = s.asTokenizableRaw(), + is TokenizableString.Raw -> { + val isAlreadyTokenized = tokenizationProcessor.decrypt( + encrypted = s.value.asTokenizableEncrypted(), tokenKeyType = tokenKeyType, project = project, - ) + logError = false, + ) is TokenizableString.Raw + + if (isAlreadyTokenized) { + s.value.asTokenizableEncrypted() + } else { + tokenizationProcessor.encrypt( + decrypted = s.value.asTokenizableRaw(), + tokenKeyType = tokenKeyType, + project = project, + ) + } } } } diff --git a/infra/enrolment-records-store/src/test/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCaseTest.kt b/infra/enrolment-records-store/src/test/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCaseTest.kt index 9308697ebf..838e1bb6a9 100644 --- a/infra/enrolment-records-store/src/test/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCaseTest.kt +++ b/infra/enrolment-records-store/src/test/java/com/simprints/infra/enrolment/records/store/usecases/CompareImplicitTokenizedStringsUseCaseTest.kt @@ -34,7 +34,7 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should return false when s1 is null`() { val s1 = null - val s2 = "s2" + val s2 = TokenizableString.Raw("s2") val result = useCase(s1, s2, tokenKeyType, project) @@ -44,7 +44,7 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should return true if strings are equal (both untokenized)`() { val s1 = "s1".asTokenizableRaw() - val s2 = s1.value + val s2 = s1 every { tokenizationProcessor.decrypt(any(), any(), any(), any()) } returns TokenizableString.Tokenized("some value") val result = useCase(s1, s2, tokenKeyType, project) @@ -56,7 +56,7 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should return false if strings are not equal (both untokenized)`() { val s1 = "s1".asTokenizableRaw() - val s2 = "s2" + val s2 = "s2".asTokenizableRaw() every { tokenizationProcessor.decrypt(any(), any(), any(), any()) } returns TokenizableString.Tokenized("some value") val result = useCase(s1, s2, tokenKeyType, project) @@ -68,7 +68,7 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should call encrypt if only first is tokenized)`() { val s1 = "s1".asTokenizableEncrypted() - val s2 = "s2" + val s2 = "s2".asTokenizableRaw() every { tokenizationProcessor.decrypt(any(), any(), any(), any()) } returns TokenizableString.Tokenized("some value") useCase(s1, s2, tokenKeyType, project) @@ -79,8 +79,8 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should call encrypt if only second is tokenized)`() { val s1 = "s1".asTokenizableRaw() - val s2 = "encrypted s1" - every { tokenizationProcessor.decrypt(any(), any(), any(), any()) } returns TokenizableString.Raw(s2) + val s2 = "encrypted s1".asTokenizableEncrypted() + every { tokenizationProcessor.decrypt(any(), any(), any(), any()) } returns TokenizableString.Tokenized("some value") useCase(s1, s2, tokenKeyType, project) @@ -90,7 +90,7 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should not call encrypt and return true if both strings are tokenized and equal`() { val s1 = "s1".asTokenizableEncrypted() - val s2 = s1.value + val s2 = "s1".asTokenizableEncrypted() every { tokenizationProcessor.decrypt(any(), any(), any(), any()) } returns TokenizableString.Raw("some value") val result = useCase(s1, s2, tokenKeyType, project) @@ -102,7 +102,7 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should not call encrypt and return false if both strings are tokenized but not equal`() { val s1 = "s1".asTokenizableEncrypted() - val s2 = "s2" + val s2 = "s2".asTokenizableEncrypted() every { tokenizationProcessor.decrypt(any(), any(), any(), any()) } returns TokenizableString.Raw("some value") val result = useCase(s1, s2, tokenKeyType, project) @@ -114,7 +114,7 @@ class CompareImplicitTokenizedStringsUseCaseTest { @Test fun `should return false if not equal`() { val s1 = "s1".asTokenizableRaw() - val s2 = "s2" + val s2 = "s2".asTokenizableRaw() val result = useCase(s1, s2, tokenKeyType, project)