TP-69604 | Firebase auth helper integrated (#11224)
Co-authored-by: Varun Jain <varun.jain@navi.com> Co-authored-by: Shivam Goyal <shivam.goyal@navi.com>
This commit is contained in:
@@ -84,6 +84,8 @@ import com.navi.chat.utils.NaviChatAnalytics.Companion.CHAT_DEEPLINK_CLICK
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.CHAT_MESSAGE
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.CHAT_MESSAGE_WIDGET_WITH_RECEIPTS_NOT_NULL
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.EXISTING_CHAT_TRIGGERED
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.FIREBASE_AUTHENTICATION_FAILURE
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.FIREBASE_AUTHENTICATION_SUCCESS
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.INSERTING_NEW_MESSAGE_TO_CHAT_ADAPTER
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.NAVI_CHAT_WIDGET
|
||||
import com.navi.chat.utils.NaviChatAnalytics.Companion.NETWORK_AVAILABLE_IN_CHAT
|
||||
@@ -101,6 +103,9 @@ import com.navi.common.constants.EMPTY
|
||||
import com.navi.common.model.common.NetworkConnectivityNudgeData
|
||||
import com.navi.common.ui.fragment.BaseFragment
|
||||
import com.navi.common.utils.Constants
|
||||
import com.navi.common.utils.FirebaseAuthHelper
|
||||
import com.navi.common.utils.FirebaseAuthStatus
|
||||
import com.navi.common.utils.getErrorData
|
||||
import com.navi.common.utils.getSessionId
|
||||
import com.navi.common.utils.log
|
||||
import com.navi.common.utils.observeNonNull
|
||||
@@ -189,6 +194,8 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb
|
||||
private var latestMessageLocation: Int? = null
|
||||
private var productConfigId: String? = null
|
||||
|
||||
@Inject lateinit var firebaseAuthHelper: FirebaseAuthHelper
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@@ -212,7 +219,6 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb
|
||||
readArguments()
|
||||
initUI()
|
||||
initObservers()
|
||||
showChatLoader()
|
||||
fetchChatData()
|
||||
fetchChatConfig()
|
||||
}
|
||||
@@ -868,7 +874,26 @@ class NaviChatFragment : BaseFragment(), WidgetCallback, MessageOperation, Toolb
|
||||
}
|
||||
|
||||
private fun fetchChatData() {
|
||||
fetchChatConversations(conversationId.orEmpty())
|
||||
showChatLoader()
|
||||
firebaseAuthHelper.isLoggedIn { status ->
|
||||
if (status is FirebaseAuthStatus.Success) {
|
||||
fetchChatConversations(conversationId.orEmpty())
|
||||
crmEventTracker.sendEvent(
|
||||
FIREBASE_AUTHENTICATION_SUCCESS,
|
||||
hashMapOf(SESSION_ID to getSessionId().orEmpty())
|
||||
)
|
||||
} else {
|
||||
setFirebaseAuthError()
|
||||
crmEventTracker.sendEvent(
|
||||
FIREBASE_AUTHENTICATION_FAILURE,
|
||||
hashMapOf(SESSION_ID to getSessionId().orEmpty())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setFirebaseAuthError() {
|
||||
naviChatViewModel.setError(listOf(getErrorData(context = requireContext())))
|
||||
}
|
||||
|
||||
private fun fetchChatConfig() {
|
||||
|
||||
@@ -159,6 +159,8 @@ class NaviChatAnalytics private constructor() {
|
||||
const val CHATSCREEN_TOP_BACK_BUTTON_CLICK = "chatscreen_top_back_button_click"
|
||||
const val SESSION_ID = "session_id"
|
||||
const val LISTEN_TO_FIRESTORE_SERVER_UPDATES = "listen_to_firestore_server_updates"
|
||||
const val FIREBASE_AUTHENTICATION_SUCCESS = "firebase_authentication_success"
|
||||
const val FIREBASE_AUTHENTICATION_FAILURE = "firebase_authentication_failure"
|
||||
|
||||
val naviChatAnalytics: NaviChatAnalytics by lazy { Holder.INSTANCE }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.common.network.models
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class FirebaseAuthTokenResponse(
|
||||
@SerializedName("externalCustomerId") val externalCustomerId: String? = null,
|
||||
@SerializedName("notificationAuthToken") val authToken: String? = null,
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2022-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2022-2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -23,9 +23,27 @@ import com.navi.common.csat.models.CSATSubmitResponse
|
||||
import com.navi.common.csat.models.NetPromoterScoreRequest
|
||||
import com.navi.common.geocoding.model.network.GeocodingRequest
|
||||
import com.navi.common.geocoding.model.network.GeocodingResponse
|
||||
import com.navi.common.model.*
|
||||
import com.navi.common.model.vkyc.*
|
||||
import com.navi.common.model.AdditionalAsyncDataResponse
|
||||
import com.navi.common.model.AsyncRequestData
|
||||
import com.navi.common.model.CommunicationAppLaunchData
|
||||
import com.navi.common.model.DeviceDetail
|
||||
import com.navi.common.model.FeedbackResponse
|
||||
import com.navi.common.model.FeedbackSubmitData
|
||||
import com.navi.common.model.KycStatus
|
||||
import com.navi.common.model.PaymentOrderDetail
|
||||
import com.navi.common.model.ProfileResponse
|
||||
import com.navi.common.model.PushNotificationData
|
||||
import com.navi.common.model.RedirectPageStatus
|
||||
import com.navi.common.model.SubmitPermissionRequestData
|
||||
import com.navi.common.model.SubmitPermissionResponse
|
||||
import com.navi.common.model.UploadDataAsyncResponse
|
||||
import com.navi.common.model.vkyc.VkycCancelStatus
|
||||
import com.navi.common.model.vkyc.VkycSettingsWithLocResponse
|
||||
import com.navi.common.model.vkyc.VkycStatus
|
||||
import com.navi.common.model.vkyc.WaitingForLongPageDetailsResponse
|
||||
import com.navi.common.model.vkyc.WaitingPageDetailsResponse
|
||||
import com.navi.common.network.BaseHttpClient
|
||||
import com.navi.common.network.models.FirebaseAuthTokenResponse
|
||||
import com.navi.common.network.models.GenericResponse
|
||||
import com.navi.common.network.models.SuccessResponse
|
||||
import com.navi.common.permission.UpdateDevicePermissionsRequest
|
||||
@@ -37,8 +55,20 @@ import com.navi.vkyc.models.PermissionDetailsResponse
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.*
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.PATCH
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
import retrofit2.http.Part
|
||||
import retrofit2.http.PartMap
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
import retrofit2.http.QueryMap
|
||||
import retrofit2.http.Tag
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface RetrofitService {
|
||||
|
||||
@@ -266,4 +296,7 @@ interface RetrofitService {
|
||||
@Header(BaseHttpClient.X_TARGET) target: String = CDS,
|
||||
@Body permissionData: SubmitPermissionRequestData
|
||||
): Response<GenericResponse<SubmitPermissionResponse>>
|
||||
|
||||
@GET("/firebase/v1/token/generate")
|
||||
suspend fun generateFirebaseAuthToken(): Response<GenericResponse<FirebaseAuthTokenResponse>>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.common.repo
|
||||
|
||||
import com.navi.common.network.retrofit.ResponseCallback
|
||||
import com.navi.common.utils.retrofitService
|
||||
import javax.inject.Inject
|
||||
|
||||
class FirebaseAuthRepository @Inject constructor() : ResponseCallback() {
|
||||
|
||||
suspend fun fetchFirebaseAuthToken() =
|
||||
apiResponseCallback(retrofitService().generateFirebaseAuthToken())
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2019-2023 by Navi Technologies Limited
|
||||
* * Copyright © 2019-2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
@@ -941,10 +941,15 @@ abstract class BaseActivity :
|
||||
|
||||
protected fun refreshFirebaseToken(authToken: String) {
|
||||
if (authToken.isEmpty()) {
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenEmpty()
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenEmpty(
|
||||
moduleName = getCurrentModuleName()
|
||||
)
|
||||
hideLoader()
|
||||
} else {
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenNotEmpty(authToken = authToken)
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenNotEmpty(
|
||||
authToken = authToken,
|
||||
moduleName = getCurrentModuleName()
|
||||
)
|
||||
FirebaseAuth.getInstance()
|
||||
.signInWithCustomToken(authToken)
|
||||
.addOnCompleteListener { task ->
|
||||
@@ -952,12 +957,14 @@ abstract class BaseActivity :
|
||||
hideLoader()
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenSigninFailure(
|
||||
authToken = authToken,
|
||||
stacktrace = task.exception?.stackTraceToString()
|
||||
stacktrace = task.exception?.stackTraceToString(),
|
||||
moduleName = getCurrentModuleName()
|
||||
)
|
||||
return@addOnCompleteListener
|
||||
}
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenSigninSuccess(
|
||||
authToken = authToken
|
||||
authToken = authToken,
|
||||
moduleName = getCurrentModuleName()
|
||||
)
|
||||
PreferenceManager.setStringPreference(
|
||||
CommonPrefConstants.USER_ID,
|
||||
@@ -968,7 +975,8 @@ abstract class BaseActivity :
|
||||
.addOnFailureListener {
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenSigninFailure(
|
||||
authToken = authToken,
|
||||
stacktrace = it.stackTraceToString()
|
||||
stacktrace = it.stackTraceToString(),
|
||||
moduleName = getCurrentModuleName()
|
||||
)
|
||||
hideLoader()
|
||||
}
|
||||
|
||||
@@ -104,29 +104,42 @@ class CommonNaviAnalytics private constructor() {
|
||||
}
|
||||
|
||||
inner class Notification {
|
||||
fun trackNotificationAuthTokenEmpty() {
|
||||
NaviTrackEvent.trackEvent(eventName = "Notification_Auth_Token_Empty")
|
||||
fun trackNotificationAuthTokenEmpty(moduleName: String) {
|
||||
NaviTrackEvent.trackEvent(
|
||||
eventName = "Notification_Auth_Token_Empty",
|
||||
eventValues = mapOf("module_name" to moduleName)
|
||||
)
|
||||
}
|
||||
|
||||
fun trackNotificationAuthTokenNotEmpty(authToken: String?) {
|
||||
fun trackNotificationAuthTokenNotEmpty(authToken: String?, moduleName: String) {
|
||||
NaviTrackEvent.trackEvent(
|
||||
eventName = "Notification_Auth_Token_Not_Empty",
|
||||
eventValues = mapOf("auth_token" to authToken.orEmpty())
|
||||
eventValues =
|
||||
mapOf("auth_token" to authToken.orEmpty(), "module_name" to moduleName)
|
||||
)
|
||||
}
|
||||
|
||||
fun trackNotificationAuthTokenSigninSuccess(authToken: String?) {
|
||||
fun trackNotificationAuthTokenSigninSuccess(authToken: String?, moduleName: String) {
|
||||
NaviTrackEvent.trackEvent(
|
||||
eventName = "Notification_Auth_Token_SignIn_Success",
|
||||
eventValues = mapOf("auth_token" to authToken.orEmpty())
|
||||
eventValues =
|
||||
mapOf("auth_token" to authToken.orEmpty(), "module_name" to moduleName)
|
||||
)
|
||||
}
|
||||
|
||||
fun trackNotificationAuthTokenSigninFailure(authToken: String?, stacktrace: String?) {
|
||||
fun trackNotificationAuthTokenSigninFailure(
|
||||
authToken: String?,
|
||||
stacktrace: String?,
|
||||
moduleName: String
|
||||
) {
|
||||
NaviTrackEvent.trackEvent(
|
||||
eventName = "Notification_Auth_Token_SignIn_Failure",
|
||||
eventValues =
|
||||
mapOf("auth_token" to authToken.orEmpty(), "stacktrace" to stacktrace.orEmpty())
|
||||
mapOf(
|
||||
"auth_token" to authToken.orEmpty(),
|
||||
"stacktrace" to stacktrace.orEmpty(),
|
||||
"module_name" to moduleName
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.common.utils
|
||||
|
||||
import com.google.firebase.auth.FirebaseAuth
|
||||
import com.navi.base.sharedpref.CommonPrefConstants
|
||||
import com.navi.base.sharedpref.PreferenceManager
|
||||
import com.navi.base.utils.BaseUtils
|
||||
import com.navi.common.model.ModuleNameV2
|
||||
import com.navi.common.repo.FirebaseAuthRepository
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class FirebaseAuthHelper @Inject constructor(private val repository: FirebaseAuthRepository) {
|
||||
private val moduleName: String = ModuleNameV2.COMMON.name
|
||||
private val notificationAnalyticsTracker = CommonNaviAnalytics.naviAnalytics.Notification()
|
||||
private val coroutineScope =
|
||||
CoroutineScope(
|
||||
Dispatchers.IO + CoroutineExceptionHandler { _, throwable -> throwable.log() }
|
||||
)
|
||||
|
||||
fun isLoggedIn(onAuth: (authStatus: FirebaseAuthStatus) -> Unit) {
|
||||
if (FirebaseAuth.getInstance().currentUser != null) {
|
||||
onAuth(FirebaseAuthStatus.Success)
|
||||
} else {
|
||||
fetchFirebaseAuthToken { authStatus -> onAuth(authStatus) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchFirebaseAuthToken(onAuth: (authStatus: FirebaseAuthStatus) -> Unit) {
|
||||
coroutineScope.launch {
|
||||
val tokenData = repository.fetchFirebaseAuthToken()
|
||||
if (tokenData.error == null && tokenData.errors.isNullOrEmpty()) {
|
||||
tokenData.data?.authToken?.let { refreshFirebaseToken(it, onAuth) }
|
||||
} else {
|
||||
onAuth(FirebaseAuthStatus.Failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshFirebaseToken(
|
||||
authToken: String,
|
||||
onAuth: (authStatus: FirebaseAuthStatus) -> Unit,
|
||||
) {
|
||||
if (authToken.isEmpty()) {
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenEmpty(moduleName = moduleName)
|
||||
} else {
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenNotEmpty(
|
||||
authToken = authToken,
|
||||
moduleName = moduleName
|
||||
)
|
||||
FirebaseAuth.getInstance()
|
||||
.signInWithCustomToken(authToken)
|
||||
.addOnCompleteListener { task ->
|
||||
if (task.isSuccessful.not()) {
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenSigninFailure(
|
||||
authToken = authToken,
|
||||
stacktrace = task.exception?.stackTraceToString(),
|
||||
moduleName = moduleName
|
||||
)
|
||||
onAuth(FirebaseAuthStatus.Failed)
|
||||
return@addOnCompleteListener
|
||||
}
|
||||
onAuth(FirebaseAuthStatus.Success)
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenSigninSuccess(
|
||||
authToken = authToken,
|
||||
moduleName = moduleName
|
||||
)
|
||||
PreferenceManager.setStringPreference(
|
||||
CommonPrefConstants.USER_ID,
|
||||
FirebaseAuth.getInstance().currentUser?.uid.orEmpty()
|
||||
)
|
||||
BaseUtils.setFirebaseTokenRefreshed(true)
|
||||
}
|
||||
.addOnFailureListener {
|
||||
notificationAnalyticsTracker.trackNotificationAuthTokenSigninFailure(
|
||||
authToken = authToken,
|
||||
stacktrace = it.stackTraceToString(),
|
||||
moduleName = moduleName
|
||||
)
|
||||
onAuth(FirebaseAuthStatus.Failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class FirebaseAuthStatus {
|
||||
data object Success : FirebaseAuthStatus()
|
||||
|
||||
data object Failed : FirebaseAuthStatus()
|
||||
}
|
||||
Reference in New Issue
Block a user