TP-60963 add generic lambda implementation (#10161)

This commit is contained in:
Hitesh Kumar
2024-04-08 19:04:03 +05:30
committed by GitHub
parent 0b09e148fd
commit 268c724e8f
36 changed files with 1311 additions and 12 deletions

View File

@@ -0,0 +1,68 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.deserializer
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.navi.ap.common.lambda.verticals.generic.event.CancelCoroutineJobEvent
import com.navi.ap.common.lambda.verticals.generic.event.CustomBanksDataFilterHandlingEvent
import com.navi.ap.common.lambda.verticals.generic.event.DelayEvent
import com.navi.ap.common.lambda.verticals.generic.event.FailureActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.PreExecutionActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.ReturnPastApiResponseEvent
import com.navi.ap.common.lambda.verticals.generic.event.SetClonedScreenDefinitionStateEvent
import com.navi.ap.common.lambda.verticals.generic.event.SuccessActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.TriggerApiEvent
import com.navi.ap.common.lambda.verticals.generic.event.UpdateAndTriggerSuccessActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.UpdateScreenDefinitionEvent
import com.navi.common.uitron.model.LambdaAppEventType
import com.navi.common.uitron.model.LambdaEventData
import java.lang.reflect.Type
class LambdaEventDeserializer : JsonDeserializer<LambdaEventData> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): LambdaEventData? {
json?.let {
val jsonObject = it.asJsonObject
val type = jsonObject["eventType"] ?: return null
return when (type.asString) {
LambdaAppEventType.CANCEL_COROUTINE_JOB.name ->
context?.deserialize(jsonObject, CancelCoroutineJobEvent::class.java)
LambdaAppEventType.PRE_EXECUTION_ACTION.name ->
context?.deserialize(jsonObject, PreExecutionActionEvent::class.java)
LambdaAppEventType.TRIGGER_API.name ->
context?.deserialize(jsonObject, TriggerApiEvent::class.java)
LambdaAppEventType.RETURN_PAST_API_RESPONSE.name ->
context?.deserialize(jsonObject, ReturnPastApiResponseEvent::class.java)
LambdaAppEventType.SUCCESS_ACTION.name ->
context?.deserialize(jsonObject, SuccessActionEvent::class.java)
LambdaAppEventType.FAILURE_ACTION.name ->
context?.deserialize(jsonObject, FailureActionEvent::class.java)
LambdaAppEventType.DELAY.name ->
context?.deserialize(jsonObject, DelayEvent::class.java)
LambdaAppEventType.UPDATE_AND_TRIGGER_SUCCESS_ACTION.name ->
context?.deserialize(jsonObject, UpdateAndTriggerSuccessActionEvent::class.java)
LambdaAppEventType.UPDATE_SCREEN_DEFINITION.name ->
context?.deserialize(jsonObject, UpdateScreenDefinitionEvent::class.java)
LambdaAppEventType.SET_CLONED_SCREEN_DEFINITION_STATE.name ->
context?.deserialize(
jsonObject,
SetClonedScreenDefinitionStateEvent::class.java
)
LambdaAppEventType.CUSTOM_BANKS_DATA_FILTER_HANDLING.name ->
context?.deserialize(jsonObject, CustomBanksDataFilterHandlingEvent::class.java)
else -> null
}
}
return null
}
}

View File

@@ -9,9 +9,14 @@ package com.navi.ap.common.lambda.handler
import com.navi.ap.common.lambda.definition.Lambda
import com.navi.ap.common.lambda.definition.LambdaBridge
import com.navi.ap.common.lambda.verticals.generic.GenericLambdaImpl
import com.navi.ap.common.models.ApScreenDefinitionStructure
import com.navi.ap.common.models.lambdamodels.LambdaData
import com.navi.ap.utils.constants.GENERIC_LAMBDA_INIT
import com.navi.ap.utils.constants.METHOD_NAME
import com.navi.ap.utils.logApEvent
import com.navi.common.uitron.model.action.LambdaApiAction
import com.navi.common.utils.Constants.TYPE
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
@@ -25,9 +30,22 @@ abstract class LambdaHandler(
clonedScreenDefinitionState.update { screenDefinitionState }
}
private val lambdaImpl by lazy { GenericLambdaImpl(lambdaHandler = this) }
fun getClonedScreenDefinitionState() = clonedScreenDefinitionState.value
override fun execute(lambdaApiAction: LambdaApiAction, lambadaData: LambdaData) {
// TODO : Put Common lambda here
}
fun executeGenericLambda(lambdaApiAction: LambdaApiAction, lambadaData: LambdaData) {
logApEvent(
Pair(TYPE, lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_INIT)
)
lambdaImpl.executeGenericLambda(
lambdaApiAction = lambdaApiAction,
resolvedValues = lambadaData.resolvedValue.toMutableMap()
)
}
}

View File

@@ -9,6 +9,7 @@ package com.navi.ap.common.lambda.verticals.coins
import com.navi.ap.common.lambda.definition.LambdaBridge
import com.navi.ap.common.lambda.handler.LambdaHandler
import com.navi.ap.common.lambda.verticals.generic.isLambdaDefinitionPresent
import com.navi.ap.common.models.lambdamodels.LambdaData
import com.navi.ap.utils.constants.LambdaType
import com.navi.common.uitron.model.action.LambdaApiAction
@@ -21,7 +22,10 @@ internal class CoinsLambdaHandler(
private val lambdaImpl by lazy { CoinLambdaImpl(lambdaHandler = this@CoinsLambdaHandler) }
override fun execute(lambdaApiAction: LambdaApiAction, lambadaData: LambdaData) {
if (isLambdaDefinitionPresent(lambdaApiAction)) {
executeGenericLambda(lambdaApiAction, lambadaData)
return
}
when (lambdaApiAction.lambdaType) {
LambdaType.VALIDATE_COINS_UPI_ID.name -> {
lambdaImpl.validateCoinsUPIId(

View File

@@ -0,0 +1,152 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic
import com.navi.analytics.utils.NaviTrackEvent
import com.navi.ap.common.lambda.getErrorBottomSheetStructureAndSetLambdaState
import com.navi.ap.common.lambda.handler.LambdaHandler
import com.navi.ap.common.lambda.verticals.generic.event.LambdaEventFactory
import com.navi.ap.common.models.LambdaResponseType
import com.navi.ap.common.models.LambdaState
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.ap.network.retrofit.ApRepoResult
import com.navi.ap.utils.constants.EVENT
import com.navi.ap.utils.constants.GENERIC_LAMBDA_HANDLE_LAMBDA_STATE
import com.navi.ap.utils.constants.GENERIC_LAMBDA_TRIGGER_OUT_OF_SCOPE
import com.navi.ap.utils.constants.GENERIC_LAMBDA_TRIGGER_SCOPE
import com.navi.ap.utils.constants.METHOD_NAME
import com.navi.ap.utils.getValueAtJsonPath
import com.navi.ap.utils.logApEvent
import com.navi.common.uitron.model.LambdaResponseInjectionField
import com.navi.common.uitron.model.LambdaStateType
import com.navi.common.uitron.model.action.ApiType
import com.navi.common.uitron.model.action.LambdaApiAction
import com.navi.common.utils.Constants
import com.navi.common.utils.log
import org.mvel2.MVEL
class GenericLambdaHelper(
val lambdaHandler: LambdaHandler,
private val lambdaEventFactory: LambdaEventFactory = LambdaEventFactory()
) {
fun handleOutOfScopeEvents(details: LambdaEventDetails) {
logApEvent(
Pair(Constants.TYPE, details.lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_TRIGGER_OUT_OF_SCOPE),
Pair(EVENT, details.lambdaEventData?.eventType.orEmpty())
)
lambdaEventFactory
.createOutOfScopeEventExecutor(type = details.lambdaEventData?.eventType)
?.handleOutOfScopeEvent(details)
}
suspend fun handleScopeEvents(details: LambdaEventDetails) {
logApEvent(
Pair(Constants.TYPE, details.lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_TRIGGER_SCOPE),
Pair(EVENT, details.lambdaEventData?.eventType.orEmpty())
)
details.lambdaEventData?.let {
lambdaEventFactory
.createScopeEventExecutor(
details = details,
handleOutOfScopeEvents = ::handleOutOfScopeEvents
)
?.handleScopeEvent(details)
}
}
fun handleLambdaState(
lambdaApiAction: LambdaApiAction,
stateType: String?,
lambdaResponse: ApRepoResult<Any> = ApRepoResult()
) {
stateType?.let {
logApEvent(
Pair(Constants.TYPE, lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_HANDLE_LAMBDA_STATE),
Pair(EVENT, it)
)
when (it) {
LambdaStateType.LOADING.name -> {
lambdaHandler.bridge.setLambdaState(LambdaState.Loading)
}
LambdaStateType.SUCCESS.name -> {
lambdaHandler.bridge.setLambdaState(LambdaState.Success(LambdaResponseType()))
}
LambdaStateType.ERROR.name -> {
lambdaHandler.bridge.setLambdaState(
LambdaState.Error(
lambdaResponse.statusCode,
lambdaResponse.errorBottomSheetStructure,
lambdaResponse.genericErrorBottomSheetFields
)
)
}
LambdaStateType.CUSTOM_ERROR.name -> {
getErrorBottomSheetStructureAndSetLambdaState(
lambdaApiAction.definition?.implementation?.apiTag
?: ApiType.LambdaApiAction.name,
lambdaResponse.statusCode
)
}
LambdaStateType.NOTHING.name -> {
lambdaHandler.bridge.setLambdaState(LambdaState.Nothing)
}
else -> {}
}
}
}
fun updateHandle(
handleConfig: List<LambdaResponseInjectionField?>?,
resolvedValues: MutableMap<String, Any?>,
lambdaResponse: ApRepoResult<Any> = ApRepoResult(),
) {
handleConfig?.forEach {
val key = getValueAtJsonPath(resolvedValues, it?.key.orEmpty()).toString()
val value =
if (it?.jsonPath.isNullOrEmpty()) {
lambdaResponse.data
} else {
getValueAtJsonPath(lambdaResponse.data ?: Any(), it?.jsonPath.orEmpty())
?: lambdaResponse.data
}
lambdaHandler.bridge.getSaveStateHandle()[key] = value
}
}
fun evaluateMvelExpression(
expression: String?,
updatedResolvedValues: MutableMap<String, Any?>,
lambdaResponse: ApRepoResult<Any> = ApRepoResult(),
pastApiResponse: HashMap<String, ApRepoResult<Any>?>
): Any? {
if (expression.isNullOrEmpty()) return null
val varsMap =
mapOf(
Pair("data", lambdaResponse.data),
Pair("errors", lambdaResponse.errors),
Pair("errorBottomSheetStructure", lambdaResponse.errorBottomSheetStructure),
Pair("resolvedValues", updatedResolvedValues),
Pair("pastApiResponse", pastApiResponse),
Pair("lambdaHandler", lambdaHandler),
)
try {
return MVEL.eval(expression, varsMap)
} catch (e: Exception) {
e.log()
NaviTrackEvent.trackEvent(
eventName = "dev_evaluate_generic_lambda_mvel_expression_result",
eventValues = mapOf(Pair("mvelExpression", expression))
)
}
return null
}
}

View File

@@ -0,0 +1,210 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic
import com.navi.ap.common.lambda.handler.LambdaHandler
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.ap.network.retrofit.ApRepoResult
import com.navi.ap.utils.constants.GENERIC_LAMBDA_PAST_API_RESPONSE
import com.navi.ap.utils.constants.GENERIC_LAMBDA_TRIGGER_POST_LAUNCH
import com.navi.ap.utils.constants.GENERIC_LAMBDA_TRIGGER_PRE_LAUNCH
import com.navi.ap.utils.constants.METHOD_NAME
import com.navi.ap.utils.constants.TRUE
import com.navi.ap.utils.logApEvent
import com.navi.common.CommonLibManager
import com.navi.common.uitron.model.action.LambdaApiAction
import com.navi.common.utils.Constants
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
internal class GenericLambdaImpl(private val lambdaHandler: LambdaHandler) {
private val repository: GenericLambdaRepository =
GenericLambdaProvider().getRepository(CommonLibManager.application.applicationContext)
private val lambdaHelper by lazy { GenericLambdaHelper(lambdaHandler) }
private val coroutineJobs by lazy { hashMapOf<String, Job>() }
private val pastApiResponse by lazy { hashMapOf<String, ApRepoResult<Any>?>() }
fun executeGenericLambda(
lambdaApiAction: LambdaApiAction,
resolvedValues: MutableMap<String, Any?>,
) {
if (areRequiredInputsPresent(lambdaApiAction, resolvedValues).not()) {
return
}
triggerPreLaunchEvents(lambdaApiAction, resolvedValues).let { isLambdaResolved ->
if (isLambdaResolved) return
}
coroutineJobs[lambdaApiAction.lambdaType.orEmpty()] =
lambdaHandler.bridge.getViewModelScope().launch(Dispatchers.IO) {
val response = triggerPostLaunchEvents(lambdaApiAction, resolvedValues)
pastApiResponse[lambdaApiAction.lambdaType.orEmpty()] = response
handleLambdaApiResponse(lambdaApiAction, resolvedValues, response)
}
}
private fun triggerPreLaunchEvents(
lambdaApiAction: LambdaApiAction,
resolvedValues: MutableMap<String, Any?>
): Boolean {
logApEvent(
Pair(Constants.TYPE, lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_TRIGGER_PRE_LAUNCH)
)
lambdaApiAction.definition?.implementation?.preLaunchEvents?.forEach { event ->
val condition = getImplementationSuccessCondition(lambdaApiAction, event)
val status = evaluateExpression(condition, resolvedValues)
handlePreLaunchLambdaStateAndAppEvents(event, status, lambdaApiAction, resolvedValues)
val handleConfig = getResponseState(lambdaApiAction, event, status)?.handleConfig
return if (handleConfig.isNullOrEmpty().not()) {
lambdaHelper.updateHandle(handleConfig, resolvedValues)
true
} else {
false
}
}
return false
}
private suspend fun triggerPostLaunchEvents(
lambdaApiAction: LambdaApiAction,
resolvedValues: MutableMap<String, Any?>
): ApRepoResult<Any> {
logApEvent(
Pair(Constants.TYPE, lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_TRIGGER_POST_LAUNCH)
)
lambdaApiAction.definition?.implementation?.postLaunchEvents?.forEach { event ->
val condition = getImplementationSuccessCondition(lambdaApiAction, event)
val status = evaluateExpression(condition, resolvedValues)
handlePostLaunchLambdaStateAndAppEvents(event, status, lambdaApiAction, resolvedValues)
if (isTriggerApiEvent(lambdaApiAction, event, status) && status == TRUE) {
return repository.triggerGenericLambda(lambdaApiAction, resolvedValues)
} else if (isPastApiResponseEvent(lambdaApiAction, event, status) && status == TRUE) {
logApEvent(
Pair(Constants.TYPE, lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_PAST_API_RESPONSE)
)
return pastApiResponse[lambdaApiAction.lambdaType.orEmpty()] ?: ApRepoResult()
}
val handleConfig = getResponseState(lambdaApiAction, event, status)?.handleConfig
if (handleConfig.isNullOrEmpty().not()) {
lambdaHelper.updateHandle(handleConfig, resolvedValues)
return ApRepoResult()
}
}
return ApRepoResult()
}
private fun handlePreLaunchLambdaStateAndAppEvents(
event: String,
status: String,
lambdaApiAction: LambdaApiAction,
resolvedValues: MutableMap<String, Any?>
) {
val lambdaState = getResponseState(lambdaApiAction, event, status)?.lambdaState
lambdaHelper.handleLambdaState(lambdaApiAction, lambdaState?.stateType)
getResponseState(lambdaApiAction, event, status)?.appEvents?.forEach { eventData ->
lambdaHelper.handleOutOfScopeEvents(
LambdaEventDetails(
lambdaEventData = eventData,
lambdaApiAction = lambdaApiAction,
resolvedValues = resolvedValues,
coroutineJobs = coroutineJobs,
lambdaHandler = lambdaHandler
)
)
}
}
private suspend fun handlePostLaunchLambdaStateAndAppEvents(
event: String,
status: String,
lambdaApiAction: LambdaApiAction,
resolvedValues: MutableMap<String, Any?>
) {
val lambdaState = getResponseState(lambdaApiAction, event, status)?.lambdaState
lambdaHelper.handleLambdaState(lambdaApiAction, lambdaState?.stateType)
getResponseState(lambdaApiAction, event, status)?.appEvents?.forEach { stateData ->
lambdaHelper.handleScopeEvents(
LambdaEventDetails(
lambdaEventData = stateData,
lambdaApiAction = lambdaApiAction,
resolvedValues = resolvedValues,
coroutineJobs = coroutineJobs,
lambdaHandler = lambdaHandler
)
)
}
}
private suspend fun handleLambdaApiResponse(
lambdaApiAction: LambdaApiAction?,
resolvedValues: MutableMap<String, Any?>,
lambdaResponse: ApRepoResult<Any>
) {
lambdaApiAction?.definition?.implementation?.conditions?.forEach { (event, state) ->
if (isEventExecuted(lambdaApiAction, event)) {
return@forEach
}
val status = evaluateExpression(state?.success, resolvedValues, lambdaResponse)
val handleConfig = getResponseState(lambdaApiAction, event, status)?.handleConfig
if (handleConfig.isNullOrEmpty().not()) {
lambdaHelper.updateHandle(handleConfig, resolvedValues, lambdaResponse)
}
val appEvents = getResponseState(lambdaApiAction, event, status)?.appEvents
appEvents?.forEach { eventData ->
lambdaHelper.handleScopeEvents(
LambdaEventDetails(
lambdaEventData = eventData,
lambdaApiAction = lambdaApiAction,
resolvedValues = resolvedValues,
coroutineJobs = coroutineJobs,
lambdaResponse = lambdaResponse,
lambdaHandler = lambdaHandler
)
)
}
val lambdaState = getResponseState(lambdaApiAction, event, status)?.lambdaState
lambdaHelper.handleLambdaState(lambdaApiAction, lambdaState?.stateType, lambdaResponse)
if (status == TRUE) {
return
}
}
}
private fun evaluateExpression(
expression: String?,
updatedResolvedValues: MutableMap<String, Any?>,
lambdaResponse: ApRepoResult<Any> = ApRepoResult()
): String {
return lambdaHelper
.evaluateMvelExpression(
expression,
updatedResolvedValues,
lambdaResponse,
pastApiResponse
)
.toString()
}
}

View File

@@ -0,0 +1,24 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic
import android.content.Context
import com.navi.ap.di.EntryPoints
import dagger.hilt.android.EntryPointAccessors
internal class GenericLambdaProvider {
fun getRepository(context: Context): GenericLambdaRepository {
val hiltEntryPoint =
EntryPointAccessors.fromApplication(
context,
EntryPoints.GenericLambdaRepositoryEntryPoint::class.java
)
return hiltEntryPoint.getGenericLambdaRepository()
}
}

View File

@@ -0,0 +1,89 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic
import com.navi.ap.data.repository.ApplicationPlatformRepositoryImp
import com.navi.ap.network.retrofit.ApRepoResult
import com.navi.ap.network.retrofit.service.APRetrofitService
import com.navi.ap.utils.constants.GENERIC_LAMBDA_TRIGGER_API
import com.navi.ap.utils.constants.METHOD_NAME
import com.navi.ap.utils.constants.RESULT
import com.navi.ap.utils.constants.STATUS_CODE
import com.navi.ap.utils.getValueAtJsonPath
import com.navi.ap.utils.injectValuesInAStringWithPlaceHolders
import com.navi.ap.utils.injector.PathInjector
import com.navi.ap.utils.logApEvent
import com.navi.common.uitron.model.ApiRequestType
import com.navi.common.uitron.model.action.ApiType
import com.navi.common.uitron.model.action.LambdaApiAction
import com.navi.common.utils.Constants
import javax.inject.Inject
class GenericLambdaRepository @Inject constructor(private val retrofitService: APRetrofitService) :
ApplicationPlatformRepositoryImp(retrofitService) {
suspend fun triggerGenericLambda(
lambdaApiAction: LambdaApiAction,
resolvedValues: MutableMap<String, Any?>,
): ApRepoResult<Any> {
logApEvent(
Pair(Constants.TYPE, lambdaApiAction.lambdaType.orEmpty()),
Pair(METHOD_NAME, GENERIC_LAMBDA_TRIGGER_API)
)
val request = lambdaApiAction.definition?.implementation?.request ?: return ApRepoResult()
val headerMap: MutableMap<String, String> = mutableMapOf()
request.headers
?.filter { it.value != null }
?.forEach {
headerMap[it.key] =
getValueAtJsonPath(resolvedValues, it.value.orEmpty()).toString()
}
val subUrl = injectValuesInAStringWithPlaceHolders(request.subUrl.orEmpty(), resolvedValues)
val requestBody =
PathInjector<Any, Any?>().injectData(request.body ?: Any(), resolvedValues)
val response =
when (request.method) {
ApiRequestType.GET.name -> {
retrofitService.getRequest(subUrl, headerMap)
}
ApiRequestType.POST.name -> {
retrofitService.postRequest(subUrl, headerMap, requestBody)
}
ApiRequestType.PATCH.name -> {
retrofitService.patchRequest(subUrl, headerMap, requestBody)
}
ApiRequestType.DELETE.name -> {
retrofitService.deleteRequest(subUrl, headerMap)
}
ApiRequestType.PUT.name -> {
retrofitService.putRequest(subUrl, headerMap, requestBody)
}
else -> {
return ApRepoResult()
}
}
logApEvent(
Pair(
RESULT,
"${response.body()?.errors} | ${response.body()?.genericErrorBottomSheetFields}"
),
Pair(METHOD_NAME, ::triggerGenericLambda.name),
Pair(STATUS_CODE, response.code().toString())
)
return apiResponseCallback(
response = response,
apiTag =
lambdaApiAction.definition?.implementation?.apiTag ?: ApiType.LambdaApiAction.name
)
}
}

View File

@@ -0,0 +1,72 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic
import com.navi.ap.utils.constants.TRUE
import com.navi.base.utils.orFalse
import com.navi.common.uitron.model.LambdaAppEventType
import com.navi.common.uitron.model.LambdaResponse
import com.navi.common.uitron.model.LambdaResponseConfig
import com.navi.common.uitron.model.action.LambdaApiAction
fun isLambdaDefinitionPresent(lambdaApiAction: LambdaApiAction): Boolean {
return lambdaApiAction.definition != null
}
fun areRequiredInputsPresent(
lambdaApiAction: LambdaApiAction,
resolvedValues: MutableMap<String, Any?>
): Boolean {
lambdaApiAction.definition?.contract?.input?.forEach {
if (it.value?.isRequired.orFalse() && resolvedValues[it.key] == null) {
return false
}
}
return true
}
fun LambdaResponse?.getSuccessOrFailureState(status: String): LambdaResponseConfig? {
return if (status == TRUE) this?.success else this?.failure
}
fun isEventExecuted(lambdaApiAction: LambdaApiAction?, event: String): Boolean {
return lambdaApiAction?.definition?.implementation?.preLaunchEvents?.contains(event) == true ||
lambdaApiAction?.definition?.implementation?.postLaunchEvents?.contains(event) == true
}
fun isTriggerApiEvent(lambdaApiAction: LambdaApiAction, event: String, status: String): Boolean {
val appEvents =
getResponseState(lambdaApiAction, event, status)?.appEvents?.map { it?.eventType }
return appEvents?.contains(LambdaAppEventType.TRIGGER_API.name).orFalse()
}
fun isPastApiResponseEvent(
lambdaApiAction: LambdaApiAction,
event: String,
status: String
): Boolean {
val appEvents =
getResponseState(lambdaApiAction, event, status)?.appEvents?.map { it?.eventType }
return appEvents?.contains(LambdaAppEventType.RETURN_PAST_API_RESPONSE.name).orFalse()
}
fun getImplementationSuccessCondition(lambdaApiAction: LambdaApiAction, event: String): String? {
return lambdaApiAction.definition?.implementation?.conditions?.get(event)?.success
}
fun getResponseState(
lambdaApiAction: LambdaApiAction,
event: String,
status: String
): LambdaResponseConfig? {
return lambdaApiAction.definition
?.implementation
?.response
?.get(event)
?.getSuccessOrFailureState(status)
}

View File

@@ -0,0 +1,18 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.common.uitron.model.LambdaEventData
class CancelCoroutineJobEvent : LambdaEventData(), ILambdaEventExecutor {
override fun handleOutOfScopeEvent(details: LambdaEventDetails) {
details.coroutineJobs[details.lambdaApiAction.lambdaType.orEmpty()]?.cancel()
}
}

View File

@@ -0,0 +1,39 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.ap.common.models.lambdamodels.response.BankDataResponse
import com.navi.ap.utils.constants.ALL_BANKS_LIST
import com.navi.ap.utils.constants.BANK_SEARCH_QUERY
import com.navi.ap.utils.constants.PREFERRED_BANKS_LIST
import com.navi.ap.utils.jsonToType
import com.navi.common.uitron.model.LambdaEventData
import com.navi.common.utils.toJsonObject
class CustomBanksDataFilterHandlingEvent : LambdaEventData(), ILambdaEventExecutor {
override suspend fun handleScopeEvent(details: LambdaEventDetails) {
val preferredBanksKey = details.resolvedValues[PREFERRED_BANKS_LIST]?.toString().orEmpty()
val allBanksKey = details.resolvedValues[ALL_BANKS_LIST]?.toString().orEmpty()
val query = details.resolvedValues[BANK_SEARCH_QUERY]?.toString().orEmpty().trim()
val banksResponse =
details.lambdaResponse.data.toJsonObject()?.jsonToType<BankDataResponse>()
details.lambdaHandler.bridge.getSaveStateHandle()[preferredBanksKey] =
if (query.isEmpty()) banksResponse?.preferredBanks else emptyList()
val filteredBanks =
banksResponse?.allSupportedBanks?.filter { it.name?.startsWith(query, true) ?: false }
details.lambdaHandler.bridge.getSaveStateHandle()[allBanksKey] = filteredBanks
if (filteredBanks?.isNotEmpty() == true) {
details.lambdaHandler.bridge.executeActions(details.lambdaApiAction.onSuccess)
} else {
details.lambdaHandler.bridge.executeActions(details.lambdaApiAction.onFailure)
}
}
}

View File

@@ -0,0 +1,26 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.google.gson.annotations.SerializedName
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.common.uitron.model.LambdaEventData
import kotlinx.coroutines.delay
class DelayEvent(@SerializedName("delay") val delay: Long? = null) :
LambdaEventData(), ILambdaEventExecutor {
override suspend fun handleScopeEvent(details: LambdaEventDetails) {
val event = details.lambdaEventData as DelayEvent
delay(event.delay ?: DEFAULT_DELAY)
}
companion object {
const val DEFAULT_DELAY = 200L
}
}

View File

@@ -0,0 +1,18 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.common.uitron.model.LambdaEventData
class FailureActionEvent : LambdaEventData(), ILambdaEventExecutor {
override fun handleOutOfScopeEvent(details: LambdaEventDetails) {
details.lambdaHandler.bridge.executeActions(details.lambdaApiAction.onFailure)
}
}

View File

@@ -0,0 +1,17 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
interface ILambdaEventExecutor {
fun handleOutOfScopeEvent(details: LambdaEventDetails) {}
suspend fun handleScopeEvent(details: LambdaEventDetails) {}
}

View File

@@ -0,0 +1,45 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.common.uitron.model.LambdaAppEventType
class LambdaEventFactory {
fun createOutOfScopeEventExecutor(type: String?): ILambdaEventExecutor? {
return when (type) {
LambdaAppEventType.CANCEL_COROUTINE_JOB.name -> CancelCoroutineJobEvent()
LambdaAppEventType.PRE_EXECUTION_ACTION.name -> PreExecutionActionEvent()
LambdaAppEventType.TRIGGER_API.name -> TriggerApiEvent()
LambdaAppEventType.SUCCESS_ACTION.name -> SuccessActionEvent()
LambdaAppEventType.FAILURE_ACTION.name -> FailureActionEvent()
else -> null
}
}
fun createScopeEventExecutor(
details: LambdaEventDetails,
handleOutOfScopeEvents: (LambdaEventDetails) -> Unit
): ILambdaEventExecutor? {
return when (details.lambdaEventData?.eventType) {
LambdaAppEventType.DELAY.name -> DelayEvent()
LambdaAppEventType.UPDATE_AND_TRIGGER_SUCCESS_ACTION.name ->
UpdateAndTriggerSuccessActionEvent()
LambdaAppEventType.UPDATE_SCREEN_DEFINITION.name -> UpdateScreenDefinitionEvent()
LambdaAppEventType.SET_CLONED_SCREEN_DEFINITION_STATE.name ->
SetClonedScreenDefinitionStateEvent()
LambdaAppEventType.CUSTOM_BANKS_DATA_FILTER_HANDLING.name ->
CustomBanksDataFilterHandlingEvent()
else -> {
handleOutOfScopeEvents.invoke(details)
return null
}
}
}
}

View File

@@ -0,0 +1,18 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.common.uitron.model.LambdaEventData
class PreExecutionActionEvent : LambdaEventData(), ILambdaEventExecutor {
override fun handleOutOfScopeEvent(details: LambdaEventDetails) {
details.lambdaHandler.bridge.executeActions(details.lambdaApiAction.preExecutionAction)
}
}

View File

@@ -0,0 +1,12 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.common.uitron.model.LambdaEventData
class ReturnPastApiResponseEvent : LambdaEventData(), ILambdaEventExecutor

View File

@@ -0,0 +1,21 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.common.uitron.model.LambdaEventData
class SetClonedScreenDefinitionStateEvent : LambdaEventData(), ILambdaEventExecutor {
override suspend fun handleScopeEvent(details: LambdaEventDetails) {
if (details.lambdaHandler.getClonedScreenDefinitionState() == null) {
details.lambdaHandler.setClonedScreenDefinitionState(
details.lambdaHandler.bridge.getScreenStructurePreRenderState()
)
}
}
}

View File

@@ -0,0 +1,18 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.common.uitron.model.LambdaEventData
class SuccessActionEvent : LambdaEventData(), ILambdaEventExecutor {
override fun handleOutOfScopeEvent(details: LambdaEventDetails) {
details.lambdaHandler.bridge.executeActions(details.lambdaApiAction.onSuccess)
}
}

View File

@@ -0,0 +1,12 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.common.uitron.model.LambdaEventData
class TriggerApiEvent : LambdaEventData(), ILambdaEventExecutor {}

View File

@@ -0,0 +1,25 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.ap.utils.injector.PathInjector
import com.navi.common.uitron.model.LambdaEventData
import com.navi.common.uitron.model.action.LambdaApiAction
class UpdateAndTriggerSuccessActionEvent : LambdaEventData(), ILambdaEventExecutor {
override suspend fun handleScopeEvent(details: LambdaEventDetails) {
val updatedLambdaApiAction =
if (details.lambdaResponse.data != null) {
PathInjector<LambdaApiAction, Any?>()
.injectData(details.lambdaApiAction, details.lambdaResponse.data)
} else details.lambdaApiAction
details.lambdaHandler.bridge.executeActions(updatedLambdaApiAction.onSuccess)
}
}

View File

@@ -0,0 +1,59 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.lambda.verticals.generic.event
import com.google.gson.annotations.SerializedName
import com.navi.ap.common.models.ApScreenDefinitionState
import com.navi.ap.common.models.ApScreenDefinitionStructure
import com.navi.ap.common.models.lambdamodels.LambdaEventDetails
import com.navi.ap.utils.injector.BasePathInjector
import com.navi.ap.utils.injector.PathInjector
import com.navi.common.uitron.model.LambdaEventData
class UpdateScreenDefinitionEvent(
@SerializedName("injectorType") val injectorType: String? = null
) : LambdaEventData(), ILambdaEventExecutor {
override suspend fun handleScopeEvent(details: LambdaEventDetails) {
val event = details.lambdaEventData as UpdateScreenDefinitionEvent
val updatedResponse = getInjectedResponse(event.injectorType, details)
updatedResponse?.let {
details.lambdaHandler.bridge.setMetaData(
updatedResponse.screenData?.metaData ?: mapOf()
)
details.lambdaHandler.bridge.setScreenDefinitionState(
ApScreenDefinitionState.Success(updatedResponse)
)
}
details.lambdaHandler.bridge.setSystemBackAction(
updatedResponse?.screenData?.screenStructure?.systemBackCta
)
}
}
suspend fun getInjectedResponse(
injectorType: String?,
details: LambdaEventDetails
): ApScreenDefinitionStructure? {
return when (injectorType) {
PathInjector.TAG -> {
PathInjector<ApScreenDefinitionStructure, Any?>()
.injectData(
details.lambdaHandler.getClonedScreenDefinitionState(),
details.lambdaResponse.data
)
}
else -> {
BasePathInjector<ApScreenDefinitionStructure, Any?>()
.injectData(
details.lambdaHandler.getClonedScreenDefinitionState(),
details.lambdaResponse.data
)
}
}
}

View File

@@ -9,6 +9,7 @@ package com.navi.ap.common.lambda.verticals.personalloan
import com.navi.ap.common.lambda.definition.LambdaBridge
import com.navi.ap.common.lambda.handler.LambdaHandler
import com.navi.ap.common.lambda.verticals.generic.isLambdaDefinitionPresent
import com.navi.ap.common.models.lambdamodels.LambdaData
import com.navi.ap.utils.constants.FILE_TYPE
import com.navi.ap.utils.constants.HYPERVERGE_PAN_FLOW_ID
@@ -33,6 +34,10 @@ open class PLLambdaHandler(
private val lambdaImpl by lazy { PLLambdaImpl(lambdaHandler = this@PLLambdaHandler) }
override fun execute(lambdaApiAction: LambdaApiAction, lambadaData: LambdaData) {
if (isLambdaDefinitionPresent(lambdaApiAction)) {
executeGenericLambda(lambdaApiAction, lambadaData)
return
}
when (lambdaApiAction.lambdaType) {
LambdaType.TELCO_RESEND_OTP.name -> {
lambdaImpl.resendTelcoOtp(lambdaApiAction = lambdaApiAction)

View File

@@ -9,6 +9,7 @@ package com.navi.ap.common.lambda.verticals.vkyc
import com.navi.ap.common.lambda.definition.LambdaBridge
import com.navi.ap.common.lambda.definition.VkycLambdaBridge
import com.navi.ap.common.lambda.verticals.generic.isLambdaDefinitionPresent
import com.navi.ap.common.lambda.verticals.personalloan.PLLambdaHandler
import com.navi.ap.common.models.lambdamodels.LambdaData
import com.navi.ap.utils.constants.LambdaType
@@ -21,6 +22,10 @@ internal class VKYCLambdaHandler(
private val lambdaImpl by lazy { VKYCLambdaImpl(lambdaHandler = this@VKYCLambdaHandler) }
override fun execute(lambdaApiAction: LambdaApiAction, lambadaData: LambdaData) {
if (isLambdaDefinitionPresent(lambdaApiAction)) {
executeGenericLambda(lambdaApiAction, lambadaData)
return
}
when (lambdaApiAction.lambdaType) {
LambdaType.CANCEL_VKYC.name -> {
(bridge as? VkycLambdaBridge)?.cancelVKYCCall(lambdaApiAction)

View File

@@ -0,0 +1,23 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.models.lambdamodels
import com.navi.ap.common.lambda.handler.LambdaHandler
import com.navi.ap.network.retrofit.ApRepoResult
import com.navi.common.uitron.model.LambdaEventData
import com.navi.common.uitron.model.action.LambdaApiAction
import kotlinx.coroutines.Job
data class LambdaEventDetails(
val lambdaEventData: LambdaEventData?,
val lambdaApiAction: LambdaApiAction,
val resolvedValues: MutableMap<String, Any?>,
val coroutineJobs: HashMap<String, Job>,
val lambdaResponse: ApRepoResult<Any> = ApRepoResult(),
val lambdaHandler: LambdaHandler
)

View File

@@ -0,0 +1,59 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.common.serializer
import com.google.gson.JsonElement
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import com.navi.ap.common.lambda.verticals.generic.event.CancelCoroutineJobEvent
import com.navi.ap.common.lambda.verticals.generic.event.CustomBanksDataFilterHandlingEvent
import com.navi.ap.common.lambda.verticals.generic.event.DelayEvent
import com.navi.ap.common.lambda.verticals.generic.event.FailureActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.PreExecutionActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.ReturnPastApiResponseEvent
import com.navi.ap.common.lambda.verticals.generic.event.SetClonedScreenDefinitionStateEvent
import com.navi.ap.common.lambda.verticals.generic.event.SuccessActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.TriggerApiEvent
import com.navi.ap.common.lambda.verticals.generic.event.UpdateAndTriggerSuccessActionEvent
import com.navi.ap.common.lambda.verticals.generic.event.UpdateScreenDefinitionEvent
import com.navi.common.uitron.model.LambdaAppEventType
import com.navi.common.uitron.model.LambdaEventData
import java.lang.reflect.Type
class LambdaEventSerializer : JsonSerializer<LambdaEventData> {
override fun serialize(
src: LambdaEventData?,
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement? {
return when (src?.eventType) {
LambdaAppEventType.CANCEL_COROUTINE_JOB.name ->
context?.serialize(src, CancelCoroutineJobEvent::class.java)
LambdaAppEventType.PRE_EXECUTION_ACTION.name ->
context?.serialize(src, PreExecutionActionEvent::class.java)
LambdaAppEventType.TRIGGER_API.name ->
context?.serialize(src, TriggerApiEvent::class.java)
LambdaAppEventType.RETURN_PAST_API_RESPONSE.name ->
context?.serialize(src, ReturnPastApiResponseEvent::class.java)
LambdaAppEventType.SUCCESS_ACTION.name ->
context?.serialize(src, SuccessActionEvent::class.java)
LambdaAppEventType.FAILURE_ACTION.name ->
context?.serialize(src, FailureActionEvent::class.java)
LambdaAppEventType.DELAY.name -> context?.serialize(src, DelayEvent::class.java)
LambdaAppEventType.UPDATE_AND_TRIGGER_SUCCESS_ACTION.name ->
context?.serialize(src, UpdateAndTriggerSuccessActionEvent::class.java)
LambdaAppEventType.UPDATE_SCREEN_DEFINITION.name ->
context?.serialize(src, UpdateScreenDefinitionEvent::class.java)
LambdaAppEventType.SET_CLONED_SCREEN_DEFINITION_STATE.name ->
context?.serialize(src, SetClonedScreenDefinitionStateEvent::class.java)
LambdaAppEventType.CUSTOM_BANKS_DATA_FILTER_HANDLING.name ->
context?.serialize(src, CustomBanksDataFilterHandlingEvent::class.java)
else -> null
}
}
}

View File

@@ -8,6 +8,7 @@
package com.navi.ap.di
import com.navi.ap.common.lambda.verticals.coins.CoinLambdaRepository
import com.navi.ap.common.lambda.verticals.generic.GenericLambdaRepository
import com.navi.ap.common.lambda.verticals.personalloan.PLLambdaRepository
import com.navi.ap.common.usecase.UploadImageToAWSUseCase
import dagger.hilt.EntryPoint
@@ -28,6 +29,12 @@ class EntryPoints {
fun getCoinLambdaRepository(): CoinLambdaRepository
}
@EntryPoint
@InstallIn(SingletonComponent::class)
interface GenericLambdaRepositoryEntryPoint {
fun getGenericLambdaRepository(): GenericLambdaRepository
}
@EntryPoint
@InstallIn(SingletonComponent::class)
interface UploadImageToAWSUseCaseEntryPoint {

View File

@@ -11,6 +11,7 @@ import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.navi.ap.common.serializer.ApUiTronActionSerializer
import com.navi.ap.common.serializer.CustomUiTronDataSerializer
import com.navi.ap.common.serializer.LambdaEventSerializer
import com.navi.ap.di.APGsonDeserializer
import com.navi.ap.di.APGsonSerializer
import com.navi.ap.network.retrofit.NaviApHttpClient
@@ -20,6 +21,7 @@ import com.navi.ap.utils.registerPLSpecificDeSerializers
import com.navi.common.CommonLibManager
import com.navi.common.model.ModuleNameV2
import com.navi.common.network.converter.EmptyBodyHandlingConverterFactory
import com.navi.common.uitron.model.LambdaEventData
import com.navi.common.uitron.model.action.ThirdPartySdkAction
import com.navi.common.uitron.model.action.UploadDataConfig
import com.navi.common.uitron.serializer.AnySerializer
@@ -79,6 +81,7 @@ object APNetworkModule {
)
.registerTypeAdapter(ThirdPartySdkAction::class.java, UiTronSDKActionSerializer())
.registerTypeAdapter(Any::class.java, AnySerializer())
.registerTypeAdapter(LambdaEventData::class.java, LambdaEventSerializer())
.create()
@Provides

View File

@@ -23,7 +23,7 @@ import com.navi.common.utils.Constants.OS_ANDROID
import retrofit2.Response
import retrofit2.http.*
interface APRetrofitService : PlLambdaService, CoinsLambdaService {
interface APRetrofitService : PlLambdaService, CoinsLambdaService, GenericLambdaService {
@POST("/arc-warden/api/v3/application/{applicationId}/screen/{screenId}")
suspend fun fetchScreenDefinition(
@Path("applicationId") applicationId: String,

View File

@@ -0,0 +1,55 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.ap.network.retrofit.service
import com.navi.common.network.models.GenericResponse
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.HeaderMap
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Url
interface GenericLambdaService {
@GET
suspend fun getRequest(
@Url url: String,
@HeaderMap headers: Map<String, String>
): Response<GenericResponse<Any>>
@POST
suspend fun postRequest(
@Url url: String,
@HeaderMap headers: Map<String, String>,
@Body requestBody: Any
): Response<GenericResponse<Any>>
@PATCH
suspend fun patchRequest(
@Url url: String,
@HeaderMap headers: Map<String, String>,
@Body requestBody: Any
): Response<GenericResponse<Any>>
@DELETE
suspend fun deleteRequest(
@Url url: String,
@HeaderMap headers: Map<String, String>
): Response<GenericResponse<Any>>
@PUT
suspend fun putRequest(
@Url url: String,
@HeaderMap headers: Map<String, String>,
@Body body: Any,
): Response<GenericResponse<Any>>
}

View File

@@ -12,6 +12,7 @@ import com.google.gson.reflect.TypeToken
import com.navi.ap.common.deserializer.ApUiTronActionDeserializer
import com.navi.ap.common.deserializer.CustomUiTronDataDeserializer
import com.navi.ap.common.deserializer.KYCSDKSettingsDataDeserializer
import com.navi.ap.common.deserializer.LambdaEventDeserializer
import com.navi.ap.common.sdk.model.KycSdkSettingData
import com.navi.ap.common.viewmodel.ApplicationPlatformVM
import com.navi.ap.utils.constants.APP_FROM_SCREEN_ID
@@ -20,6 +21,7 @@ import com.navi.ap.utils.constants.DEFAULT_SOURCE_SCREEN
import com.navi.base.model.CtaData
import com.navi.base.utils.EMPTY
import com.navi.base.utils.orElse
import com.navi.common.uitron.model.LambdaEventData
import com.navi.common.utils.log
import com.navi.common.utils.registerUiTronDeSerializers
import com.navi.payment.model.clientmodels.PaymentEvent
@@ -97,6 +99,7 @@ fun GsonBuilder.registerApUiTronDeSerializers(): GsonBuilder {
return registerUiTronDeSerializers().apply {
registerTypeAdapter(UiTronData::class.java, CustomUiTronDataDeserializer())
registerTypeAdapter(UiTronAction::class.java, ApUiTronActionDeserializer())
registerTypeAdapter(LambdaEventData::class.java, LambdaEventDeserializer())
}
}

View File

@@ -27,14 +27,19 @@ import com.navi.ap.common.ui.ApplicationPlatformActivity
import com.navi.ap.network.di.APNetworkModule.providesDeserializer
import com.navi.ap.network.di.APNetworkModule.providesSerializer
import com.navi.ap.screens.genericscreen.vm.ApGenericScreenVM
import com.navi.ap.utils.constants.CODE
import com.navi.ap.utils.constants.DEFAULT_SCREEN_STATE_ID
import com.navi.ap.utils.constants.DEFAULT_SOURCE_SCREEN
import com.navi.ap.utils.constants.DOT_SDK_DOT
import com.navi.ap.utils.constants.JOURNEY_SOURCE
import com.navi.ap.utils.constants.KEY_PAYMENT_GATEWAY_EVENT_NAME
import com.navi.ap.utils.constants.KEY_PAYMENT_SDK_VERSION
import com.navi.ap.utils.constants.LATITUDE
import com.navi.ap.utils.constants.LAYOUT_ID
import com.navi.ap.utils.constants.LONGITUDE
import com.navi.ap.utils.constants.METHOD_NAME
import com.navi.ap.utils.constants.PARENT
import com.navi.ap.utils.constants.PAYMENT_DOT_GATEWAY_DOT
import com.navi.ap.utils.constants.SOURCE_AP
import com.navi.ap.utils.constants.VIEW_ID
import com.navi.ap.utils.constants.WIDGET_ID
@@ -47,6 +52,8 @@ import com.navi.common.utils.CommonUtils
import com.navi.common.utils.EMPTY
import com.navi.common.utils.getDeviceData
import com.navi.common.utils.log
import com.navi.payment.utils.Constants
import com.navi.payment.utils.PaymentAnalytics.PROVIDER
import com.navi.uitron.model.UiTronResponse
import com.navi.uitron.utils.getInputId
import com.navi.uitron.utils.isNull
@@ -177,6 +184,15 @@ fun getResolvedFieldValue(
val output: String? = handle[name]
map[item.sourceProperty.orEmpty()] = "${output.orEmpty()}$valueSuffix"
}
SourceType.DEVICE_PROPERTY.name -> {
val value =
getDeviceData(
sourceProperty = item.sourceProperty.orEmpty(),
context = CommonLibManager.application.applicationContext,
additionalValues = item.additionalParameters
)
map[name] = value
}
SourceType.PRE_DEFINED.name -> {
map[name] = "${item.value.orEmpty()}$valueSuffix"
}
@@ -185,14 +201,16 @@ fun getResolvedFieldValue(
val output = readJsonPath(obj.toJson(), item.jsonPath.orEmpty())
map[item.sourceProperty.orEmpty()] = "$output$valueSuffix"
}
SourceType.DEVICE_PROPERTY.name -> {
val value =
getDeviceData(
sourceProperty = item.sourceProperty.orEmpty(),
context = CommonLibManager.application.applicationContext,
additionalValues = item.additionalParameters
)
map[item.name.orEmpty()] = value
SourceType.CONSTANTS.name -> {
map[name] =
when (item.sourceProperty) {
KEY_PAYMENT_SDK_VERSION -> Constants.PAYMENT_SDK_VERSION
else -> EMPTY
}
}
SourceType.CUSTOM_LOGIC.name -> {
val value = getCustomFieldData(item.sourceProperty.orEmpty(), map)
map[name] = value
}
else -> Unit
}
@@ -323,3 +341,38 @@ fun buildFillParametersUsingWidgetOutput(
)
}
}
fun getCustomFieldData(sourceProperty: String, map: MutableMap<String, Any?>? = null): String {
return when (sourceProperty) {
KEY_PAYMENT_GATEWAY_EVENT_NAME -> {
getPaymentGatewayEventName(map?.get(CODE).toString(), map?.get(PROVIDER).toString())
}
else -> EMPTY
}
}
private fun getPaymentGatewayEventName(code: String, provider: String): String {
return "$PAYMENT_DOT_GATEWAY_DOT$provider$DOT_SDK_DOT$code"
}
fun injectValuesInAStringWithPlaceHolders(text: String, dataObj: Any): String {
val placeholders = text.split("{").drop(1).map { it.split("}")[0] }
var result = text
placeholders.forEach { placeholder ->
val value = (getValueAtJsonPath(dataObj, placeholder) ?: EMPTY).toString()
result = result.replace("{$placeholder}", value)
}
return result
}
fun getValueAtJsonPath(dataObj: Any, jsonPath: String): Any? {
return try {
val dataObject = JSONObject(dataObj.toJson())
readJsonPath(dataObject.toString(), jsonPath)
} catch (e: Exception) {
e.log()
null
}
}

View File

@@ -62,6 +62,7 @@ const val WIDGET_ID = "widgetId"
const val PARENT = "parent"
const val INVALID_IFSC_CODE = "INVALID_IFSC_CODE"
const val SOURCE = "source"
const val EVENT = "event"
val noLoaderScreenTypes: MutableSet<String> =
mutableSetOf(
@@ -85,3 +86,7 @@ const val SELECTED_DATE_WITH_SUFFIX = "selectedDateWithSuffix"
const val SELECTED_FORMATTED_DATE = "selectedFormattedDate"
const val SHOW = "show"
const val INVALID_PIN_CODE = "INVALID_PIN_CODE"
const val KEY_PAYMENT_SDK_VERSION = "KEY_PAYMENT_SDK_VERSION"
const val KEY_PAYMENT_GATEWAY_EVENT_NAME = "paymentGatewayEventName"
const val PAYMENT_DOT_GATEWAY_DOT = "payments.gateway."
const val DOT_SDK_DOT = ".sdk."

View File

@@ -62,3 +62,13 @@ const val DIGILOCKER = "digilocker"
// HYPERVERGE PAN
const val HYPERVERGE_PAN_CAPTURE_SUCCESS = "hyperverge_pan_capture_success"
const val HYPERVERGE_PAN_CAPTURE_ERROR = "hyperverge_pan_capture_error"
// GENERIC LAMBDA
const val GENERIC_LAMBDA_INIT = "generic_lambda_init"
const val GENERIC_LAMBDA_TRIGGER_PRE_LAUNCH = "generic_lambda_trigger_pre_launch"
const val GENERIC_LAMBDA_TRIGGER_POST_LAUNCH = "generic_lambda_trigger_post_launch"
const val GENERIC_LAMBDA_TRIGGER_API = "generic_lambda_trigger_api"
const val GENERIC_LAMBDA_PAST_API_RESPONSE = "generic_lambda_past_api_response"
const val GENERIC_LAMBDA_TRIGGER_OUT_OF_SCOPE = "generic_lambda_trigger_out_of_scope"
const val GENERIC_LAMBDA_TRIGGER_SCOPE = "generic_lambda_trigger_scope"
const val GENERIC_LAMBDA_HANDLE_LAMBDA_STATE = "generic_lambda_handle_lambda_state"

View File

@@ -13,6 +13,11 @@ import org.json.JSONArray
import org.json.JSONObject
class PathInjector<U, V> : BasePathInjector<U, V>() {
companion object {
const val TAG = "PATH_INJECTOR"
}
override fun inject(currentObject: JSONObject, key: String, type: JSON_TYPE) {
when (type) {
JSON_TYPE.JSONArray -> {