Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import com.simprints.face.capture.FaceCaptureResult
import com.simprints.face.capture.models.FaceDetection
import com.simprints.face.capture.usecases.BitmapToByteArrayUseCase
import com.simprints.face.capture.usecases.IsUsingAutoCaptureUseCase
import com.simprints.face.capture.usecases.SaveFaceImageUseCase
import com.simprints.face.capture.usecases.SaveFaceSampleUseCase
import com.simprints.face.capture.usecases.ShouldShowInstructionsScreenUseCase
import com.simprints.face.capture.usecases.SimpleCaptureEventReporter
import com.simprints.face.infra.biosdkresolver.ResolveFaceBioSdkUseCase
Expand Down Expand Up @@ -47,7 +47,7 @@ import javax.inject.Inject
internal class FaceCaptureViewModel @Inject constructor(
private val authStore: AuthStore,
private val configManager: ConfigManager,
private val saveFaceImage: SaveFaceImageUseCase,
private val saveFaceImage: SaveFaceSampleUseCase,
private val eventReporter: SimpleCaptureEventReporter,
private val bitmapToByteArray: BitmapToByteArrayUseCase,
private val licenseRepository: LicenseRepository,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.simprints.face.capture.usecases

import com.simprints.infra.config.store.models.GeneralConfiguration
import com.simprints.infra.events.session.SessionEventRepository
import com.simprints.infra.images.ImageRepository
import com.simprints.infra.images.model.SecuredImageRef
import javax.inject.Inject

internal class SaveFaceSampleUseCase @Inject constructor(
private val coreImageRepository: ImageRepository,
private val sessionEventRepository: SessionEventRepository,
) {
suspend operator fun invoke(
imageBytes: ByteArray,
captureEventId: String,
): SecuredImageRef? {
val sessionScope = try {
sessionEventRepository.getCurrentSessionScope()
} catch (_: Throwable) {
return null
}

return coreImageRepository.storeSample(
projectId = sessionScope.projectId,
sessionId = sessionScope.id,
modality = GeneralConfiguration.Modality.FACE,
sampleId = captureEventId,
fileExtension = "jpg",
sampleBytes = imageBytes,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.simprints.core.tools.time.Timestamp
import com.simprints.face.capture.models.FaceDetection
import com.simprints.face.capture.usecases.BitmapToByteArrayUseCase
import com.simprints.face.capture.usecases.IsUsingAutoCaptureUseCase
import com.simprints.face.capture.usecases.SaveFaceImageUseCase
import com.simprints.face.capture.usecases.SaveFaceSampleUseCase
import com.simprints.face.capture.usecases.ShouldShowInstructionsScreenUseCase
import com.simprints.face.capture.usecases.SimpleCaptureEventReporter
import com.simprints.face.infra.basebiosdk.initialization.FaceBioSdkInitializer
Expand Down Expand Up @@ -54,7 +54,7 @@ class FaceCaptureViewModelTest {
private lateinit var configManager: ConfigManager

@MockK
private lateinit var faceImageUseCase: SaveFaceImageUseCase
private lateinit var faceImageUseCase: SaveFaceSampleUseCase

@MockK
private lateinit var eventReporter: SimpleCaptureEventReporter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test

class SaveFaceImageUseCaseTest {
class SaveFaceSampleUseCaseTest {
@MockK
lateinit var imageRepo: ImageRepository

@MockK
lateinit var eventRepo: SessionEventRepository

private lateinit var useCase: SaveFaceImageUseCase
private lateinit var useCase: SaveFaceSampleUseCase

@Before
fun setUp() {
MockKAnnotations.init(this, relaxed = true)

useCase = SaveFaceImageUseCase(imageRepo, eventRepo)
useCase = SaveFaceSampleUseCase(imageRepo, eventRepo)
}

@Test
Expand All @@ -40,32 +40,23 @@ class SaveFaceImageUseCaseTest {

val expectedPath = Path(
arrayOf(
"sessions",
"sessions",
"sessionId",
"faces",
"captureEventId.jpg",
),
)
coEvery {
imageRepo.storeImageSecurely(any(), "projectId", any())
imageRepo.storeSample("projectId", "sessionId", any(), any(), any(), any())
} returns SecuredImageRef(expectedPath)

val imageBytes = byteArrayOf()
val captureEventId = "captureEventId"

assertThat(useCase.invoke(imageBytes, captureEventId)).isNotNull()

coVerify {
imageRepo.storeImageSecurely(
withArg {
assert(it.isEmpty())
},
"projectId",
withArg {
assert(expectedPath.compose().contains(it.compose()))
},
)
}
coVerify { imageRepo.storeSample(any(), any(), any(), any(), any(), any()) }
}

@Test
Expand All @@ -85,13 +76,13 @@ class SaveFaceImageUseCaseTest {
every { id } returns "sessionId"
}
coEvery {
imageRepo.storeImageSecurely(any(), "projectId", any())
imageRepo.storeSample("projectId", "sessionId", any(), "captureEventId", "jpg", any())
} returns null

val imageBytes = byteArrayOf()
val captureEventId = "captureEventId"

assertThat(useCase.invoke(imageBytes, captureEventId)).isNull()
coVerify { imageRepo.storeImageSecurely(any(), "projectId", any()) }
coVerify { imageRepo.storeSample(any(), any(), any(), any(), any(), any()) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import com.simprints.fingerprint.capture.usecase.AddCaptureEventsUseCase
import com.simprints.fingerprint.capture.usecase.GetNextFingerToAddUseCase
import com.simprints.fingerprint.capture.usecase.GetStartStateUseCase
import com.simprints.fingerprint.capture.usecase.IsNoFingerDetectedLimitReachedUseCase
import com.simprints.fingerprint.capture.usecase.SaveImageUseCase
import com.simprints.fingerprint.capture.usecase.SaveFingerprintSampleUseCase
import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException
import com.simprints.fingerprint.infra.biosdk.BioSdkWrapper
import com.simprints.fingerprint.infra.biosdk.ResolveBioSdkWrapperUseCase
Expand Down Expand Up @@ -72,7 +72,7 @@ internal class FingerprintCaptureViewModel @Inject constructor(
private val configManager: ConfigManager,
private val timeHelper: TimeHelper,
private val resolveBioSdkWrapperUseCase: ResolveBioSdkWrapperUseCase,
private val saveImage: SaveImageUseCase,
private val saveImage: SaveFingerprintSampleUseCase,
private val getNextFingerToAdd: GetNextFingerToAddUseCase,
private val getStartState: GetStartStateUseCase,
private val addCaptureEvents: AddCaptureEventsUseCase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import com.simprints.fingerprint.capture.extensions.deduceFileExtension
import com.simprints.fingerprint.capture.extensions.toInt
import com.simprints.fingerprint.capture.state.CaptureState
import com.simprints.fingerprint.infra.scanner.v2.scanner.ScannerInfo
import com.simprints.infra.config.store.models.GeneralConfiguration
import com.simprints.infra.config.store.models.Vero2Configuration
import com.simprints.infra.events.session.SessionEventRepository
import com.simprints.infra.images.ImageRepository
import com.simprints.infra.images.model.Path
import com.simprints.infra.images.model.SecuredImageRef
import com.simprints.infra.logging.LoggingConstants.CrashReportTag.FACE_CAPTURE
import com.simprints.infra.logging.Simber
import javax.inject.Inject

internal class SaveImageUseCase @Inject constructor(
internal class SaveFingerprintSampleUseCase @Inject constructor(
private val coreImageRepository: ImageRepository,
private val coreEventRepository: SessionEventRepository,
private val scannerInfo: ScannerInfo,
Expand Down Expand Up @@ -49,54 +49,31 @@ internal class SaveImageUseCase @Inject constructor(
dpi: Int,
scannerId: String?,
un20SerialNumber: String?,
): SecuredImageRef? = determinePath(captureEventId, fileExtension)?.let { path ->
Simber.d("Saving fingerprint image $path", tag = FACE_CAPTURE)
val currentSession = coreEventRepository.getCurrentSessionScope()
val projectId = currentSession.projectId
): SecuredImageRef? {
val currentSession = try {
coreEventRepository.getCurrentSessionScope()
} catch (_: Throwable) {
return null
}

val securedImageRef = coreImageRepository.storeImageSecurely(
imageBytes = imageBytes,
projectId = projectId,
relativePath = Path(path.parts),
metadata = mutableMapOf(
return coreImageRepository.storeSample(
projectId = currentSession.projectId,
sessionId = currentSession.id,
modality = GeneralConfiguration.Modality.FINGERPRINT,
sampleId = captureEventId,
fileExtension = fileExtension,
sampleBytes = imageBytes,
optionalMetadata = mutableMapOf(
META_KEY_FINGER_ID to finger.name,
META_KEY_DPI to dpi.toString(),
).apply {
scannerId?.let { this[META_KEY_SCANNER_ID] = it }
un20SerialNumber?.let { this[META_KEY_UN20_SERIAL_NUMBER] = it }
},
)

if (securedImageRef != null) {
SecuredImageRef(Path(securedImageRef.relativePath.parts))
} else {
Simber.i("Saving image failed for captureId $captureEventId", tag = FACE_CAPTURE)
null
}
}

private suspend fun determinePath(
captureEventId: String,
fileExtension: String,
): Path? = try {
val sessionId = coreEventRepository.getCurrentSessionScope().id
Path(
arrayOf(
SESSIONS_PATH,
sessionId,
FINGERPRINTS_PATH,
"$captureEventId.$fileExtension",
),
)
} catch (t: Throwable) {
Simber.e("Failed to determine path for captureId $captureEventId", t, tag = FACE_CAPTURE)
null
}

companion object {
const val SESSIONS_PATH = "sessions"
const val FINGERPRINTS_PATH = "fingerprints"

companion object Companion {
private const val META_KEY_DPI = "dpi"
private const val META_KEY_FINGER_ID = "finger"
private const val META_KEY_SCANNER_ID = "scannerID"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import com.simprints.fingerprint.capture.usecase.AddCaptureEventsUseCase
import com.simprints.fingerprint.capture.usecase.GetNextFingerToAddUseCase
import com.simprints.fingerprint.capture.usecase.GetStartStateUseCase
import com.simprints.fingerprint.capture.usecase.IsNoFingerDetectedLimitReachedUseCase
import com.simprints.fingerprint.capture.usecase.SaveImageUseCase
import com.simprints.fingerprint.capture.usecase.SaveFingerprintSampleUseCase
import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException
import com.simprints.fingerprint.infra.biosdk.BioSdkWrapper
import com.simprints.fingerprint.infra.biosdk.ResolveBioSdkWrapperUseCase
Expand Down Expand Up @@ -99,7 +99,7 @@ class FingerprintCaptureViewModelTest {
private lateinit var timeHelper: TimeHelper

@MockK
private lateinit var saveImageUseCase: SaveImageUseCase
private lateinit var saveFingerprintSampleUseCase: SaveFingerprintSampleUseCase

@MockK
private lateinit var addCaptureEventsUseCase: AddCaptureEventsUseCase
Expand Down Expand Up @@ -153,7 +153,7 @@ class FingerprintCaptureViewModelTest {
configManager = configManager,
timeHelper = timeHelper,
resolveBioSdkWrapperUseCase = resolveBioSdkWrapperUseCase,
saveImage = saveImageUseCase,
saveImage = saveFingerprintSampleUseCase,
getNextFingerToAdd = getNextFingerToAddUseCase,
getStartState = getStartStateUseCase,
addCaptureEvents = addCaptureEventsUseCase,
Expand Down Expand Up @@ -518,7 +518,7 @@ class FingerprintCaptureViewModelTest {
)
coVerify(exactly = 12) { addCaptureEventsUseCase.invoke(any(), any(), any(), any()) }
vm.handleConfirmFingerprintsAndContinue()
coVerify(exactly = 4) { saveImageUseCase.invoke(any(), any(), any(), any()) }
coVerify(exactly = 4) { saveFingerprintSampleUseCase.invoke(any(), any(), any(), any()) }

coVerify { addBiometricReferenceCreatedEvents.invoke(any(), any()) }
vm.finishWithFingerprints.assertEventReceivedWithContentAssertions { actualFingerprints ->
Expand Down Expand Up @@ -577,7 +577,7 @@ class FingerprintCaptureViewModelTest {
coVerify(exactly = 2) { addCaptureEventsUseCase.invoke(any(), any(), any(), any()) }

vm.handleConfirmFingerprintsAndContinue()
coVerify(exactly = 2) { saveImageUseCase.invoke(any(), any(), any(), any()) }
coVerify(exactly = 2) { saveFingerprintSampleUseCase.invoke(any(), any(), any(), any()) }
coVerify { addBiometricReferenceCreatedEvents.invoke(any(), any()) }

vm.finishWithFingerprints.assertEventReceivedWithContentAssertions { actualFingerprints ->
Expand Down Expand Up @@ -634,7 +634,7 @@ class FingerprintCaptureViewModelTest {
)
coVerify(exactly = 2) { addCaptureEventsUseCase.invoke(any(), any(), any(), any()) }
vm.handleConfirmFingerprintsAndContinue()
coVerify(exactly = 0) { saveImageUseCase.invoke(any(), any(), any(), any()) }
coVerify(exactly = 0) { saveFingerprintSampleUseCase.invoke(any(), any(), any(), any()) }
coVerify { addBiometricReferenceCreatedEvents.invoke(any(), any()) }

vm.finishWithFingerprints.assertEventReceivedWithContentAssertions { actualFingerprints ->
Expand Down Expand Up @@ -849,7 +849,7 @@ class FingerprintCaptureViewModelTest {
coVerify(exactly = 14) { addCaptureEventsUseCase.invoke(any(), any(), any(), any()) }

vm.handleConfirmFingerprintsAndContinue()
coVerify(exactly = 3) { saveImageUseCase.invoke(any(), any(), any(), any()) }
coVerify(exactly = 3) { saveFingerprintSampleUseCase.invoke(any(), any(), any(), any()) }

vm.finishWithFingerprints.assertEventReceivedWithContentAssertions { actualFingerprints ->
assertThat(actualFingerprints?.results).hasSize(3)
Expand Down Expand Up @@ -960,7 +960,7 @@ class FingerprintCaptureViewModelTest {

coVerify(exactly = 14) { addCaptureEventsUseCase.invoke(any(), any(), any(), any()) }
// If eager, expect that images were saved before confirm was pressed, including bad scans
coVerify(exactly = 8) { saveImageUseCase.invoke(any(), any(), any(), any()) }
coVerify(exactly = 8) { saveFingerprintSampleUseCase.invoke(any(), any(), any(), any()) }

vm.handleConfirmFingerprintsAndContinue()

Expand Down Expand Up @@ -1057,7 +1057,7 @@ class FingerprintCaptureViewModelTest {

vm.handleConfirmFingerprintsAndContinue()
// Save image is called even if scanResult.image == null
coVerify(exactly = 3) { saveImageUseCase.invoke(any(), any(), any(), any()) }
coVerify(exactly = 3) { saveFingerprintSampleUseCase.invoke(any(), any(), any(), any()) }

vm.finishWithFingerprints.assertEventReceivedWithContentAssertions { actualFingerprints ->
assertThat(actualFingerprints?.results).hasSize(3)
Expand Down Expand Up @@ -1468,7 +1468,7 @@ class FingerprintCaptureViewModelTest {

private fun withImageTransfer(strategy: ImageSavingStrategy = ImageSavingStrategy.ONLY_USED_IN_REFERENCE) {
every { vero2Configuration.imageSavingStrategy } returns strategy
coEvery { saveImageUseCase.invoke(any(), any(), any(), any()) } returns mockk {
coEvery { saveFingerprintSampleUseCase.invoke(any(), any(), any(), any()) } returns mockk {
every { relativePath } returns Path(emptyArray())
}
}
Expand Down
Loading