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
Expand Up @@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope
import com.simprints.core.livedata.LiveDataEvent
import com.simprints.core.livedata.LiveDataEventWithContent
import com.simprints.core.livedata.send
import com.simprints.core.tools.extentions.isValidGuid

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be addressed in a separate PR app-wide.

import com.simprints.core.tools.extentions.toJsonElementMap
import com.simprints.core.tools.time.TimeHelper
import com.simprints.feature.clientapi.exceptions.InvalidRequestException
Expand Down Expand Up @@ -153,6 +154,19 @@ class ClientApiViewModel @Inject internal constructor(
val currentSessionId = getCurrentSessionId()
simpleEventReporter.addCompletionCheckEvent(flowCompleted = true)

val selectedGuid = (action as? ActionRequest.ConfirmIdentityActionRequest)
?.selectedGuid
?.takeIf { it.isValidGuid() }
val coSyncEnrolmentRecords = if (
confirmResponse.identificationOutcome &&
confirmResponse.externalCredential != null &&
selectedGuid != null
) {
getEnrolmentCreationEventForRecord(action.projectId, selectedGuid)
} else {
null
}

deleteSessionEventsIfNeeded(currentSessionId)

logIntent(action, currentSessionId, "Confirmed: ${confirmResponse.identificationOutcome}")
Expand All @@ -163,6 +177,7 @@ class ClientApiViewModel @Inject internal constructor(
actionIdentifier = action.actionIdentifier,
sessionId = currentSessionId,
confirmed = confirmResponse.identificationOutcome,
subjectActions = coSyncEnrolmentRecords,
externalCredential = confirmResponse.externalCredential,
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal class CommCareResponseMapper @Inject constructor(
CommCareConstants.COMMCARE_SID_VERSION to appVersionName,
CommCareConstants.SIMPRINTS_SESSION_ID to response.sessionId,
CommCareConstants.BIOMETRICS_COMPLETE_CHECK_KEY to "true",
).toCommCareBundle()
).appendCoSyncData(response.subjectActions).toCommCareBundle()

is ActionResponse.VerifyActionResponse -> bundleOf(
CommCareConstants.COMMCARE_DEVICE_ID to deviceId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ internal class LibSimprintsResponseMapper @Inject constructor(
Constants.SIMPRINTS_APP_VERSION_NAME to appVersionName,
Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK to true,
Constants.SIMPRINTS_HAS_CREDENTIAL to (response.externalCredential != null),
).appendExternalCredential(response.externalCredential)
).appendCoSyncData(response.subjectActions)
.appendExternalCredential(response.externalCredential)
}

is ActionResponse.VerifyActionResponse -> bundleOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ internal class ClientApiViewModelTest {
@Test
fun `handleConfirmResponse saves correct events`() = runTest {
viewModel.handleConfirmResponse(
mockRequest(),
mockConfirmRequest(),
mockk {
every { identificationOutcome } returns true
every { externalCredential } returns mockk()
Expand All @@ -210,13 +210,65 @@ internal class ClientApiViewModelTest {

coVerify {
simpleEventReporter.addCompletionCheckEvent(eq(true))
getEnrolmentCreationEventForRecord.invoke("projectId", SELECTED_GUID)
deleteSessionEventsIfNeeded(any())
persistentLogger.log(any(), any(), any(), any())
}
verify { resultMapper.invoke(match<ActionResponse> { it is ActionResponse.ConfirmActionResponse }) }
viewModel.returnResponse.test().assertHasValue()
}

@Test
fun `handleConfirmResponse does not generate cosync when no credential`() = runTest {
viewModel.handleConfirmResponse(
mockConfirmRequest(),
mockk {
every { identificationOutcome } returns true
every { externalCredential } returns null
},
)

coVerify(exactly = 0) {
getEnrolmentCreationEventForRecord.invoke(any(), any())
}
verify { resultMapper.invoke(match<ActionResponse> { it is ActionResponse.ConfirmActionResponse }) }
viewModel.returnResponse.test().assertHasValue()
}

@Test
fun `handleConfirmResponse does not generate cosync when identification outcome is false`() = runTest {
viewModel.handleConfirmResponse(
mockConfirmRequest(),
mockk {
every { identificationOutcome } returns false
every { externalCredential } returns mockk()
},
)

coVerify(exactly = 0) {
getEnrolmentCreationEventForRecord.invoke(any(), any())
}
verify { resultMapper.invoke(match<ActionResponse> { it is ActionResponse.ConfirmActionResponse }) }
viewModel.returnResponse.test().assertHasValue()
}

@Test
fun `handleConfirmResponse does not generate cosync when no subject selected`() = runTest {
viewModel.handleConfirmResponse(
mockConfirmRequest(guid = NONE_SELECTED),
mockk {
every { identificationOutcome } returns true
every { externalCredential } returns mockk()
},
)

coVerify(exactly = 0) {
getEnrolmentCreationEventForRecord.invoke(any(), any())
}
verify { resultMapper.invoke(match<ActionResponse> { it is ActionResponse.ConfirmActionResponse }) }
viewModel.returnResponse.test().assertHasValue()
}

@Test
fun `handleVerifyResponse saves correct events`() = runTest {
viewModel.handleVerifyResponse(
Expand Down Expand Up @@ -308,4 +360,15 @@ internal class ClientApiViewModelTest {
every { projectId } returns "projectId"
every { actionIdentifier } returns ActionRequestIdentifier("action", "package", "", 1, 0L)
}

private fun mockConfirmRequest(guid: String = SELECTED_GUID): ActionRequest.ConfirmIdentityActionRequest = mockk {
every { projectId } returns "projectId"
every { selectedGuid } returns guid
every { actionIdentifier } returns ActionRequestIdentifier("action", "package", "", 1, 0L)
}

companion object {
private const val SELECTED_GUID = "0b7a26c1-0d4d-4e1b-9c50-1cb3d1e0d1f2"
private const val NONE_SELECTED = "NONE_SELECTED"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class ActionToIntentMapperTest {
actionIdentifier = ConfirmIdentityActionFactory.getIdentifier().copy(packageName = packageName),
sessionId = "sessionId",
confirmed = true,
subjectActions = null,
externalCredential = null,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class CommCareResponseMapperTest {
actionIdentifier = ConfirmIdentityActionFactory.getIdentifier(),
sessionId = "sessionId",
confirmed = true,
subjectActions = null,
externalCredential = null,
),
).getBundle(CommCareConstants.COMMCARE_BUNDLE_KEY) ?: bundleOf()
Expand All @@ -98,6 +99,21 @@ class CommCareResponseMapperTest {
assertThat(extras.getString(CommCareConstants.BIOMETRICS_COMPLETE_CHECK_KEY)).isEqualTo("true")
}

@Test
fun `correctly maps confirm response with cosync data`() {
val extras = mapper(
ActionResponse.ConfirmActionResponse(
actionIdentifier = ConfirmIdentityActionFactory.getIdentifier(),
sessionId = "sessionId",
confirmed = true,
subjectActions = "cosyncJson",
externalCredential = null,
),
).getBundle(CommCareConstants.COMMCARE_BUNDLE_KEY) ?: bundleOf()

assertThat(extras.getString(Constants.SIMPRINTS_COSYNC_SUBJECT_ACTIONS)).isEqualTo("cosyncJson")
}

@Test
fun `correctly maps verify response with null verificationSuccess`() {
val extras = mapper(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class LibSimprintsResponseMapperTest {
actionIdentifier = ConfirmIdentityActionFactory.getIdentifier(),
sessionId = "sessionId",
confirmed = true,
subjectActions = null,
externalCredential = mockk {
every { value } returns expectedValue
every { type } returns expectedType
Expand All @@ -162,6 +163,21 @@ class LibSimprintsResponseMapperTest {
assertThat(extras.getString(Constants.SIMPRINTS_SCANNED_CREDENTIAL)).isEqualTo(expectedJson)
}

@Test
fun `correctly maps confirm response with cosync data`() {
val extras = mapper(
ActionResponse.ConfirmActionResponse(
actionIdentifier = ConfirmIdentityActionFactory.getIdentifier(),
sessionId = "sessionId",
confirmed = true,
subjectActions = "cosyncJson",
externalCredential = null,
),
)

assertThat(extras.getString(Constants.SIMPRINTS_COSYNC_SUBJECT_ACTIONS)).isEqualTo("cosyncJson")
}

@Test
fun `correctly maps verify response with null verificationSuccess`() {
val extras = mapper(
Expand Down Expand Up @@ -435,6 +451,7 @@ class LibSimprintsResponseMapperTest {
actionIdentifier = ConfirmIdentityActionFactory.getIdentifier(),
sessionId = "sessionId",
confirmed = true,
subjectActions = null,
externalCredential = null,
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class OdkResponseMapperTest {
actionIdentifier = ConfirmIdentityActionFactory.getIdentifier(),
sessionId = "sessionId",
confirmed = true,
subjectActions = null,
externalCredential = null,
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ sealed class ActionResponse(
override val actionIdentifier: ActionRequestIdentifier,
override val sessionId: String,
val confirmed: Boolean,
val subjectActions: String?,
val externalCredential: AppExternalCredential?,
) : ActionResponse(actionIdentifier, sessionId)

Expand Down