diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b5581c340..c5ca19ae1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -37,6 +37,12 @@ + + + + + + { - if (viewModel.isLogistrationEnabled) { + val authCode = authCode; + if (viewModel.isLogistrationEnabled && authCode == null) { addFragment(LogistrationFragment()) } else { - addFragment(SignInFragment()) + val bundle = Bundle() + bundle.putString("auth_code", authCode) + val fragment = SignInFragment() + fragment.arguments = bundle + addFragment(fragment) } } diff --git a/app/src/main/java/org/openedx/app/di/AppModule.kt b/app/src/main/java/org/openedx/app/di/AppModule.kt index 860e98de0..60d8a52ff 100644 --- a/app/src/main/java/org/openedx/app/di/AppModule.kt +++ b/app/src/main/java/org/openedx/app/di/AppModule.kt @@ -20,6 +20,7 @@ import org.openedx.app.room.DATABASE_NAME import org.openedx.app.system.notifier.AppNotifier import org.openedx.auth.presentation.AuthAnalytics import org.openedx.auth.presentation.AuthRouter +import org.openedx.auth.presentation.sso.BrowserAuthHelper import org.openedx.auth.presentation.sso.FacebookAuthHelper import org.openedx.auth.presentation.sso.GoogleAuthHelper import org.openedx.auth.presentation.sso.MicrosoftAuthHelper @@ -153,4 +154,5 @@ val appModule = module { factory { FacebookAuthHelper() } factory { GoogleAuthHelper(get()) } factory { MicrosoftAuthHelper() } + factory { BrowserAuthHelper(get()) } } diff --git a/app/src/main/java/org/openedx/app/di/ScreenModule.kt b/app/src/main/java/org/openedx/app/di/ScreenModule.kt index 96fc024d0..31115ebf5 100644 --- a/app/src/main/java/org/openedx/app/di/ScreenModule.kt +++ b/app/src/main/java/org/openedx/app/di/ScreenModule.kt @@ -74,6 +74,7 @@ val screenModule = module { get(), get(), get(), + get(), courseId, ) } diff --git a/auth/build.gradle b/auth/build.gradle index 02b94a587..d2ab1cc0c 100644 --- a/auth/build.gradle +++ b/auth/build.gradle @@ -55,6 +55,7 @@ android { dependencies { implementation project(path: ':core') + implementation 'androidx.browser:browser:1.7.0' implementation "androidx.credentials:credentials:1.2.0" implementation "androidx.credentials:credentials-play-services-auth:1.2.0" implementation "com.facebook.android:facebook-login:16.2.0" diff --git a/auth/src/main/java/org/openedx/auth/data/api/AuthApi.kt b/auth/src/main/java/org/openedx/auth/data/api/AuthApi.kt index 903cbd62e..6d40554ea 100644 --- a/auth/src/main/java/org/openedx/auth/data/api/AuthApi.kt +++ b/auth/src/main/java/org/openedx/auth/data/api/AuthApi.kt @@ -32,6 +32,14 @@ interface AuthApi { @Field("asymmetric_jwt") isAsymmetricJwt: Boolean = true, ): AuthResponse + @FormUrlEncoded + @POST(ApiConstants.URL_ACCESS_TOKEN) + suspend fun getAccessTokenFromCode( + @Field("grant_type") grantType: String, + @Field("client_id") clientId: String, + @Field("code") code: String, + ): AuthResponse + @FormUrlEncoded @POST(ApiConstants.URL_ACCESS_TOKEN) fun refreshAccessToken( diff --git a/auth/src/main/java/org/openedx/auth/data/model/AuthType.kt b/auth/src/main/java/org/openedx/auth/data/model/AuthType.kt index 5addd621c..c56ba0cf1 100644 --- a/auth/src/main/java/org/openedx/auth/data/model/AuthType.kt +++ b/auth/src/main/java/org/openedx/auth/data/model/AuthType.kt @@ -13,4 +13,5 @@ enum class AuthType(val postfix: String, val methodName: String) { GOOGLE(ApiConstants.AUTH_TYPE_GOOGLE, "Google"), FACEBOOK(ApiConstants.AUTH_TYPE_FB, "Facebook"), MICROSOFT(ApiConstants.AUTH_TYPE_MICROSOFT, "Microsoft"), + BROWSER(ApiConstants.AUTH_TYPE_BROWSER, "Browser") } diff --git a/auth/src/main/java/org/openedx/auth/data/repository/AuthRepository.kt b/auth/src/main/java/org/openedx/auth/data/repository/AuthRepository.kt index 6cf54a7f1..5c7e464cb 100644 --- a/auth/src/main/java/org/openedx/auth/data/repository/AuthRepository.kt +++ b/auth/src/main/java/org/openedx/auth/data/repository/AuthRepository.kt @@ -1,5 +1,6 @@ package org.openedx.auth.data.repository +import android.util.Log import org.openedx.auth.data.api.AuthApi import org.openedx.auth.data.model.AuthType import org.openedx.auth.data.model.ValidationFields @@ -43,6 +44,14 @@ class AuthRepository( .processAuthResponse() } + suspend fun browserAuthCodeLogin(code: String) { + api.getAccessTokenFromCode( + grantType = ApiConstants.GRANT_TYPE_CODE, + clientId = config.getOAuthClientId(), + code = code, + ).mapToDomain().processAuthResponse() + } + suspend fun getRegistrationFields(): List { return api.getRegistrationFields().fields?.map { it.mapToDomain() } ?: emptyList() } @@ -60,12 +69,16 @@ class AuthRepository( } private suspend fun AuthResponse.processAuthResponse() { + Log.d("MMMMMMMM", error.toString()) if (error != null) { throw EdxError.UnknownException(error!!) } preferencesManager.accessToken = accessToken ?: "" preferencesManager.refreshToken = refreshToken ?: "" preferencesManager.accessTokenExpiresAt = getTokenExpiryTime() + Log.d("MMMMMMMM", preferencesManager.accessToken) + Log.d("MMMMMMMM", preferencesManager.refreshToken) + Log.d("MMMMMMMM", preferencesManager.accessTokenExpiresAt.toString()) val user = api.getProfile() preferencesManager.user = user } diff --git a/auth/src/main/java/org/openedx/auth/domain/interactor/AuthInteractor.kt b/auth/src/main/java/org/openedx/auth/domain/interactor/AuthInteractor.kt index 00fe509af..d81c51eaf 100644 --- a/auth/src/main/java/org/openedx/auth/domain/interactor/AuthInteractor.kt +++ b/auth/src/main/java/org/openedx/auth/domain/interactor/AuthInteractor.kt @@ -18,6 +18,10 @@ class AuthInteractor(private val repository: AuthRepository) { repository.socialLogin(token, authType) } + suspend fun loginAuthCode(authCode: String) { + repository.browserAuthCodeLogin(authCode) + } + suspend fun getRegistrationFields(): List { return repository.getRegistrationFields() } diff --git a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt index 5c77688c3..a53e04ac5 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/logistration/LogistrationFragment.kt @@ -1,6 +1,8 @@ package org.openedx.auth.presentation.logistration +import android.content.Intent import android.content.res.Configuration +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup @@ -41,6 +43,8 @@ import androidx.fragment.app.Fragment import org.koin.android.ext.android.inject import org.openedx.auth.R import org.openedx.auth.presentation.AuthRouter +import org.openedx.core.config.Config +import org.openedx.core.presentation.dialog.alert.ActionDialogFragment import org.openedx.core.ui.AuthButtonsPanel import org.openedx.core.ui.SearchBar import org.openedx.core.ui.displayCutoutForLandscape @@ -48,11 +52,13 @@ import org.openedx.core.ui.noRippleClickable import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appTypography +import org.openedx.core.utils.UrlUtils import org.openedx.core.R as coreR class LogistrationFragment : Fragment() { private val router: AuthRouter by inject() + private val config: Config by inject() override fun onCreateView( inflater: LayoutInflater, @@ -68,7 +74,15 @@ class LogistrationFragment : Fragment() { router.navigateToSignIn(parentFragmentManager, courseId) }, onRegisterClick = { - router.navigateToSignUp(parentFragmentManager, courseId) + if (config.isBrowserRegistrationEnabled()) { + UrlUtils.openInBrowser( + activity = context, + apiHostUrl = config.getApiHostURL(), + url = "/register", + ) + } else { + router.navigateToSignUp(parentFragmentManager, courseId) + } }, onSearchClick = { querySearch -> router.navigateToDiscoverCourses(parentFragmentManager, querySearch) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInFragment.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInFragment.kt index 12eeedc7d..84fff3146 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInFragment.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInFragment.kt @@ -1,6 +1,7 @@ package org.openedx.auth.presentation.signin import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import androidx.compose.runtime.LaunchedEffect @@ -44,6 +45,11 @@ class SignInFragment : Fragment() { val appUpgradeEvent by viewModel.appUpgradeEvent.observeAsState(null) if (appUpgradeEvent == null) { + val authCode = arguments?.getString("auth_code") + if (authCode is String && !state.loginFailure && !state.loginSuccess) { + arguments?.remove("auth_code") + viewModel.signInAuthCode(authCode) + } LoginScreen( windowSize = windowSize, state = state, @@ -65,6 +71,10 @@ class SignInFragment : Fragment() { router.navigateToRestorePassword(parentFragmentManager) } + AuthEvent.SignInBrowser -> { + viewModel.signInBrowser(requireActivity()) + } + AuthEvent.RegisterClick -> { viewModel.signUpClickedEvent() router.navigateToSignUp(parentFragmentManager, null) @@ -117,7 +127,9 @@ internal sealed interface AuthEvent { object SignInGoogle : AuthEvent object SignInFacebook : AuthEvent object SignInMicrosoft : AuthEvent + object SignInBrowser : AuthEvent object RegisterClick : AuthEvent object ForgotPasswordClick : AuthEvent object BackClick : AuthEvent + } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt index 829d376f1..7231c9ed6 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInUIState.kt @@ -15,7 +15,10 @@ internal data class SignInUIState( val isGoogleAuthEnabled: Boolean = false, val isMicrosoftAuthEnabled: Boolean = false, val isSocialAuthEnabled: Boolean = false, + val isBrowserLoginEnabled: Boolean = false, + val isBrowserRegistrationEnabled: Boolean = false, val isLogistrationEnabled: Boolean = false, val showProgress: Boolean = false, val loginSuccess: Boolean = false, + val loginFailure: Boolean = false, ) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt index 4ab688e21..a93fb08f8 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/SignInViewModel.kt @@ -15,6 +15,7 @@ import org.openedx.auth.R import org.openedx.auth.data.model.AuthType import org.openedx.auth.domain.interactor.AuthInteractor import org.openedx.auth.presentation.AuthAnalytics +import org.openedx.auth.presentation.sso.BrowserAuthHelper import org.openedx.auth.presentation.sso.FacebookAuthHelper import org.openedx.auth.presentation.sso.GoogleAuthHelper import org.openedx.auth.presentation.sso.MicrosoftAuthHelper @@ -42,6 +43,7 @@ class SignInViewModel( private val facebookAuthHelper: FacebookAuthHelper, private val googleAuthHelper: GoogleAuthHelper, private val microsoftAuthHelper: MicrosoftAuthHelper, + private val browserAuthHelper: BrowserAuthHelper, val config: Config, val courseId: String?, ) : BaseViewModel() { @@ -53,6 +55,8 @@ class SignInViewModel( isFacebookAuthEnabled = config.getFacebookConfig().isEnabled(), isGoogleAuthEnabled = config.getGoogleConfig().isEnabled(), isMicrosoftAuthEnabled = config.getMicrosoftConfig().isEnabled(), + isBrowserLoginEnabled = config.isBrowserLoginEnabled(), + isBrowserRegistrationEnabled = config.isBrowserRegistrationEnabled(), isSocialAuthEnabled = config.isSocialAuthEnabled(), isLogistrationEnabled = config.isPreLoginExperienceEnabled(), ) @@ -140,6 +144,17 @@ class SignInViewModel( } } + fun signInBrowser(activityContext: Activity) { + _uiState.update { it.copy(showProgress = true) } + viewModelScope.launch { + runCatching { + browserAuthHelper.signIn(activityContext) + }.onFailure { + logger.e { "Browser auth error: $it" } + } + } + } + fun signInMicrosoft(activityContext: Activity) { _uiState.update { it.copy(showProgress = true) } viewModelScope.launch { @@ -155,6 +170,26 @@ class SignInViewModel( } } + fun signInAuthCode(authCode: String) { + _uiState.update { it.copy(showProgress = true) } + viewModelScope.launch { + runCatching { + interactor.loginAuthCode(authCode) + } + .onFailure { + logger.e { "OAuth2 code error: $it" } + onUnknownError() + _uiState.update { it.copy(loginFailure = true) } + }.onSuccess { + logger.d { "Browser login success" } + _uiState.update { it.copy(loginSuccess = true) } + setUserId() + analytics.userLoginEvent(AuthType.BROWSER.methodName) + _uiState.update { it.copy(showProgress = false) } + } + } + } + fun signUpClickedEvent() { analytics.signUpClickedEvent() } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index 2aed9869c..e49997e52 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -206,49 +206,55 @@ private fun AuthForm( var password by rememberSaveable { mutableStateOf("") } Column(horizontalAlignment = Alignment.CenterHorizontally) { - LoginTextField( - modifier = Modifier - .fillMaxWidth(), - onValueChanged = { - login = it - }) + if (!state.isBrowserLoginEnabled) { + LoginTextField( + modifier = Modifier + .fillMaxWidth(), + onValueChanged = { + login = it + }) - Spacer(modifier = Modifier.height(18.dp)) - PasswordTextField( - modifier = Modifier - .fillMaxWidth(), - onValueChanged = { - password = it - }, - onPressDone = { - onEvent(AuthEvent.SignIn(login = login, password = password)) - } - ) + Spacer(modifier = Modifier.height(18.dp)) + PasswordTextField( + modifier = Modifier + .fillMaxWidth(), + onValueChanged = { + password = it + }, + onPressDone = { + onEvent(AuthEvent.SignIn(login = login, password = password)) + } + ) + } else { + Spacer(modifier = Modifier.height(40.dp)) + } Row( Modifier .fillMaxWidth() .padding(top = 20.dp, bottom = 36.dp) ) { - if (state.isLogistrationEnabled.not()) { + if (!state.isBrowserLoginEnabled) { + if (state.isLogistrationEnabled.not()) { + Text( + modifier = Modifier.noRippleClickable { + onEvent(AuthEvent.RegisterClick) + }, + text = stringResource(id = coreR.string.core_register), + color = MaterialTheme.appColors.primary, + style = MaterialTheme.appTypography.labelLarge + ) + } + Spacer(modifier = Modifier.weight(1f)) Text( modifier = Modifier.noRippleClickable { - onEvent(AuthEvent.RegisterClick) + onEvent(AuthEvent.ForgotPasswordClick) }, - text = stringResource(id = coreR.string.core_register), + text = stringResource(id = R.string.auth_forgot_password), color = MaterialTheme.appColors.primary, style = MaterialTheme.appTypography.labelLarge ) } - Spacer(modifier = Modifier.weight(1f)) - Text( - modifier = Modifier.noRippleClickable { - onEvent(AuthEvent.ForgotPasswordClick) - }, - text = stringResource(id = R.string.auth_forgot_password), - color = MaterialTheme.appColors.primary, - style = MaterialTheme.appTypography.labelLarge - ) } if (state.showProgress) { @@ -258,7 +264,11 @@ private fun AuthForm( width = buttonWidth, text = stringResource(id = coreR.string.core_sign_in), onClick = { - onEvent(AuthEvent.SignIn(login = login, password = password)) + if(state.isBrowserLoginEnabled) { + onEvent(AuthEvent.SignInBrowser) + } else { + onEvent(AuthEvent.SignIn(login = login, password = password)) + } } ) } @@ -413,6 +423,24 @@ private fun SignInScreenPreview() { } } +@Preview(uiMode = UI_MODE_NIGHT_NO) +@Preview(uiMode = UI_MODE_NIGHT_YES) +@Preview(name = "NEXUS_5_Light", device = Devices.NEXUS_5, uiMode = UI_MODE_NIGHT_NO) +@Preview(name = "NEXUS_5_Dark", device = Devices.NEXUS_5, uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun SignInUsingBrowserScreenPreview() { + OpenEdXTheme { + LoginScreen( + windowSize = WindowSize(WindowType.Compact, WindowType.Compact), + state = SignInUIState().copy( + isBrowserLoginEnabled = true, + ), + uiMessage = null, + onEvent = {}, + ) + } +} + @Preview(name = "NEXUS_9_Light", device = Devices.NEXUS_9, uiMode = UI_MODE_NIGHT_NO) @Preview(name = "NEXUS_9_Night", device = Devices.NEXUS_9, uiMode = UI_MODE_NIGHT_YES) diff --git a/auth/src/main/java/org/openedx/auth/presentation/sso/BrowserAuthHelper.kt b/auth/src/main/java/org/openedx/auth/presentation/sso/BrowserAuthHelper.kt new file mode 100644 index 000000000..5822babd6 --- /dev/null +++ b/auth/src/main/java/org/openedx/auth/presentation/sso/BrowserAuthHelper.kt @@ -0,0 +1,32 @@ +package org.openedx.auth.presentation.sso + +import android.app.Activity +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.net.Uri +import androidx.annotation.WorkerThread +import androidx.browser.customtabs.CustomTabsIntent +import org.openedx.core.config.Config +import org.openedx.core.utils.Logger + +class BrowserAuthHelper(private val config: Config) { + + private val logger = Logger(TAG) + + @WorkerThread + suspend fun signIn(activityContext: Activity) { + logger.d { "Browser-based auth initiated" } + val uri = Uri.parse("${config.getApiHostURL()}/oauth2/authorize").buildUpon() + .appendQueryParameter("client_id", config.getOAuthClientId()) + .appendQueryParameter("redirect_uri", "${activityContext.packageName}://oauth2Callback") + .appendQueryParameter("response_type", "code").build() + val intent = + CustomTabsIntent.Builder().setUrlBarHidingEnabled(true).setShowTitle(true).build() + intent.intent.setFlags(FLAG_ACTIVITY_NEW_TASK) + logger.d { "Launching custom tab with ${uri.toString()}"} + intent.launchUrl(activityContext, uri) + } + + private companion object { + const val TAG = "BrowserAuthHelper" + } +} diff --git a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt index 9e5e13be0..ff2e53ab6 100644 --- a/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt +++ b/auth/src/test/java/org/openedx/auth/presentation/signin/SignInViewModelTest.kt @@ -24,6 +24,7 @@ import org.junit.rules.TestRule import org.openedx.auth.R import org.openedx.auth.domain.interactor.AuthInteractor import org.openedx.auth.presentation.AuthAnalytics +import org.openedx.auth.presentation.sso.BrowserAuthHelper import org.openedx.auth.presentation.sso.FacebookAuthHelper import org.openedx.auth.presentation.sso.GoogleAuthHelper import org.openedx.auth.presentation.sso.MicrosoftAuthHelper @@ -59,6 +60,7 @@ class SignInViewModelTest { private val facebookAuthHelper = mockk() private val googleAuthHelper = mockk() private val microsoftAuthHelper = mockk() + private val browserAuthHelper = mockk() private val invalidCredential = "Invalid credentials" private val noInternet = "Slow or no internet connection" @@ -82,6 +84,8 @@ class SignInViewModelTest { every { config.getFacebookConfig() } returns FacebookConfig() every { config.getGoogleConfig() } returns GoogleConfig() every { config.getMicrosoftConfig() } returns MicrosoftConfig() + every { config.isBrowserLoginEnabled() } returns false + every { config.isBrowserRegistrationEnabled() } returns false } @After @@ -105,6 +109,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) viewModel.login("", "") @@ -134,6 +139,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) viewModel.login("acc@test.o", "") @@ -165,6 +171,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) viewModel.login("acc@test.org", "") @@ -195,6 +202,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) viewModel.login("acc@test.org", "ed") @@ -227,6 +235,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) coEvery { interactor.login("acc@test.org", "edx") } returns Unit @@ -260,6 +269,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) coEvery { interactor.login("acc@test.org", "edx") } throws UnknownHostException() @@ -294,6 +304,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) coEvery { interactor.login("acc@test.org", "edx") } throws EdxError.InvalidGrantException() @@ -328,6 +339,7 @@ class SignInViewModelTest { googleAuthHelper = googleAuthHelper, microsoftAuthHelper = microsoftAuthHelper, config = config, + browserAuthHelper = browserAuthHelper, courseId = "", ) coEvery { interactor.login("acc@test.org", "edx") } throws IllegalStateException() diff --git a/core/src/main/java/org/openedx/core/ApiConstants.kt b/core/src/main/java/org/openedx/core/ApiConstants.kt index 091a09f42..2909bbc31 100644 --- a/core/src/main/java/org/openedx/core/ApiConstants.kt +++ b/core/src/main/java/org/openedx/core/ApiConstants.kt @@ -12,6 +12,7 @@ object ApiConstants { const val URL_PASSWORD_RESET = "/password_reset/" const val GRANT_TYPE_PASSWORD = "password" + const val GRANT_TYPE_CODE = "authorization_code" const val TOKEN_TYPE_BEARER = "Bearer" const val TOKEN_TYPE_JWT = "jwt" @@ -23,4 +24,5 @@ object ApiConstants { const val AUTH_TYPE_GOOGLE = "google-oauth2" const val AUTH_TYPE_FB = "facebook" const val AUTH_TYPE_MICROSOFT = "azuread-oauth2" + const val AUTH_TYPE_BROWSER = "browser" } diff --git a/core/src/main/java/org/openedx/core/config/Config.kt b/core/src/main/java/org/openedx/core/config/Config.kt index 27aeee158..9332f8de7 100644 --- a/core/src/main/java/org/openedx/core/config/Config.kt +++ b/core/src/main/java/org/openedx/core/config/Config.kt @@ -95,6 +95,14 @@ class Config(context: Context) { return getBoolean(COURSE_UNIT_PROGRESS_ENABLED, false) } + fun isBrowserLoginEnabled(): Boolean { + return getBoolean(BROWSER_LOGIN, false) + } + + fun isBrowserRegistrationEnabled(): Boolean { + return getBoolean(BROWSER_REGISTRATION, false) + } + private fun getString(key: String, defaultValue: String): String { val element = getObject(key) return if (element != null) { @@ -143,6 +151,8 @@ class Config(context: Context) { private const val GOOGLE = "GOOGLE" private const val MICROSOFT = "MICROSOFT" private const val PRE_LOGIN_EXPERIENCE_ENABLED = "PRE_LOGIN_EXPERIENCE_ENABLED" + private const val BROWSER_LOGIN = "BROWSER_LOGIN" + private const val BROWSER_REGISTRATION = "BROWSER_REGISTRATION" private const val DISCOVERY = "DISCOVERY" private const val COURSE_NESTED_LIST_ENABLED = "COURSE_NESTED_LIST_ENABLED" private const val COURSE_BANNER_ENABLED = "COURSE_BANNER_ENABLED"