Skip to content

Commit

Permalink
feat: login with Google, Facebook, Microsoft
Browse files Browse the repository at this point in the history
  • Loading branch information
k1rill committed Nov 14, 2023
1 parent b23156f commit bfb58db
Show file tree
Hide file tree
Showing 31 changed files with 1,179 additions and 447 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ jobs:
uses: gradle/[email protected]
with:
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}

- name: Generate mock files
run: ./gradlew generateMockedRawFile
- name: Run unit tests
run: ./gradlew testProdReleaseUnitTest $CI_GRADLE_ARG_PROPERTIES

Expand Down
15 changes: 14 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import org.yaml.snakeyaml.Yaml

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.yaml:snakeyaml:1.33'
}
}

plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
Expand All @@ -6,11 +17,13 @@ plugins {
id 'com.google.firebase.crashlytics'
}

def config = new Yaml().load(new File("config.yaml").newInputStream())

android {
compileSdk 34

defaultConfig {
applicationId "org.openedx.app"
applicationId config.applicationId
minSdk 24
targetSdk 34
versionCode 1
Expand Down
37 changes: 22 additions & 15 deletions app/src/main/java/org/openedx/app/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,31 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import kotlinx.coroutines.Dispatchers
import org.koin.android.ext.koin.androidApplication
import org.koin.core.qualifier.named
import org.koin.dsl.module
import org.openedx.app.AnalyticsManager
import org.openedx.app.AppAnalytics
import org.openedx.app.AppRouter
import org.openedx.app.data.storage.PreferencesManager
import org.openedx.app.room.AppDatabase
import org.openedx.app.room.DATABASE_NAME
import org.openedx.app.system.notifier.AppNotifier
import org.openedx.auth.presentation.sso.FacebookAuthHelper
import org.openedx.auth.presentation.sso.GoogleAuthHelper
import org.openedx.auth.presentation.sso.MicrosoftAuthHelper
import org.openedx.auth.presentation.AuthAnalytics
import org.openedx.auth.presentation.AuthRouter
import org.openedx.app.data.storage.PreferencesManager
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.module.DownloadWorkerController
import org.openedx.core.module.TranscriptManager
import org.openedx.core.module.download.FileDownloader
import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRouter
import org.openedx.core.system.AppCookieManager
import org.openedx.core.system.ResourceManager
import org.openedx.core.system.connection.NetworkConnection
import org.openedx.core.system.notifier.AppUpgradeNotifier
import org.openedx.core.system.notifier.CourseNotifier
import org.openedx.course.presentation.CourseAnalytics
import org.openedx.course.presentation.CourseRouter
Expand All @@ -23,23 +39,10 @@ import org.openedx.discovery.presentation.DiscoveryRouter
import org.openedx.discussion.presentation.DiscussionAnalytics
import org.openedx.discussion.presentation.DiscussionRouter
import org.openedx.discussion.system.notifier.DiscussionNotifier
import org.openedx.app.AnalyticsManager
import org.openedx.app.AppAnalytics
import org.openedx.app.AppRouter
import org.openedx.app.room.AppDatabase
import org.openedx.app.room.DATABASE_NAME
import org.openedx.app.system.notifier.AppNotifier
import org.openedx.profile.data.storage.ProfilePreferences
import org.openedx.profile.presentation.ProfileAnalytics
import org.openedx.profile.presentation.ProfileRouter
import org.openedx.profile.system.notifier.ProfileNotifier
import kotlinx.coroutines.Dispatchers
import org.koin.android.ext.koin.androidApplication
import org.koin.core.qualifier.named
import org.koin.dsl.module
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRouter
import org.openedx.core.system.notifier.AppUpgradeNotifier
import org.openedx.profile.data.storage.ProfilePreferences
import org.openedx.whatsnew.WhatsNewFileManager
import org.openedx.whatsnew.WhatsNewRouter
import org.openedx.whatsnew.data.storage.WhatsNewPreferences
Expand Down Expand Up @@ -133,4 +136,8 @@ val appModule = module {
single<ProfileAnalytics> { get<AnalyticsManager>() }
single<CourseAnalytics> { get<AnalyticsManager>() }
single<DiscussionAnalytics> { get<AnalyticsManager>() }

single { FacebookAuthHelper() }
single { GoogleAuthHelper() }
single { MicrosoftAuthHelper() }
}
2 changes: 1 addition & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ val screenModule = module {
factory { AuthRepository(get(), get()) }
factory { AuthInteractor(get()) }
factory { Validator() }
viewModel { SignInViewModel(get(), get(), get(), get(), get(), get()) }
viewModel { SignInViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get()) }
viewModel { SignUpViewModel(get(), get(), get(), get(), get()) }
viewModel { RestorePasswordViewModel(get(), get(), get(), get()) }

Expand Down
7 changes: 6 additions & 1 deletion auth/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ android {
dependencies {
implementation project(path: ':core')

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"
implementation "com.google.android.gms:play-services-auth:20.7.0"
implementation "com.google.android.libraries.identity.googleid:googleid:1.1.0"
implementation 'com.microsoft.identity.client:msal:4.9.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
Expand All @@ -64,5 +70,4 @@ dependencies {
testImplementation "io.mockk:mockk-android:$mockk_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
testImplementation "androidx.arch.core:core-testing:$android_arch_version"

}
7 changes: 6 additions & 1 deletion auth/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

-if class androidx.credentials.CredentialManager
-keep class androidx.credentials.playservices.** {
*;
}
10 changes: 10 additions & 0 deletions auth/src/main/java/org/openedx/auth/data/api/AuthApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ import retrofit2.http.*

interface AuthApi {

@FormUrlEncoded
@POST(ApiConstants.URL_EXCHANGE_TOKEN)
suspend fun exchangeAccessToken(
@Field("access_token") accessToken: String,
@Field("client_id") clientId: String,
@Field("token_type") tokenType: String,
@Field("asymmetric_jwt") isAsymmetricJwt: Boolean = true,
@Path("login_type") loginType: String,
): AuthResponse

@FormUrlEncoded
@POST(ApiConstants.URL_ACCESS_TOKEN)
suspend fun getAccessToken(
Expand Down
16 changes: 16 additions & 0 deletions auth/src/main/java/org/openedx/auth/data/model/LoginType.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.openedx.auth.data.model

import org.openedx.core.ApiConstants

/**
* Enum class with types of supported login types
*
* @param postfix postfix to add to the API call
* @param methodName name of the login type
*/
enum class LoginType(val postfix: String, val methodName: String) {
PASSWORD("", "Password"),
GOOGLE(ApiConstants.LOGIN_TYPE_GOOGLE, "Google"),
FACEBOOK(ApiConstants.LOGIN_TYPE_FB, "Facebook"),
MICROSOFT(ApiConstants.LOGIN_TYPE_MICROSOFT, "Microsoft"),
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.openedx.auth.data.repository

import org.openedx.auth.data.api.AuthApi
import org.openedx.auth.data.model.LoginType
import org.openedx.auth.data.model.ValidationFields
import org.openedx.core.ApiConstants
import org.openedx.core.BuildConfig
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.domain.model.RegistrationField
import org.openedx.core.system.EdxError
Expand All @@ -18,10 +20,27 @@ class AuthRepository(
) {
val authResponse = api.getAccessToken(
ApiConstants.GRANT_TYPE_PASSWORD,
org.openedx.core.BuildConfig.CLIENT_ID,
BuildConfig.CLIENT_ID,
username,
password,
org.openedx.core.BuildConfig.ACCESS_TOKEN_TYPE
BuildConfig.ACCESS_TOKEN_TYPE
)
if (authResponse.error != null) {
throw EdxError.UnknownException(authResponse.error!!)
}
preferencesManager.accessToken = authResponse.accessToken ?: ""
preferencesManager.refreshToken = authResponse.refreshToken ?: ""
val user = api.getProfile()
preferencesManager.user = user
}

suspend fun socialLogin(token: String?, loginType: LoginType) {
if (token.isNullOrBlank()) throw IllegalArgumentException("Token is null")
val authResponse = api.exchangeAccessToken(
accessToken = token,
clientId = BuildConfig.CLIENT_ID,
tokenType = BuildConfig.ACCESS_TOKEN_TYPE,
loginType = loginType.postfix
)
if (authResponse.error != null) {
throw EdxError.UnknownException(authResponse.error!!)
Expand All @@ -47,4 +66,4 @@ class AuthRepository(
suspend fun passwordReset(email: String): Boolean {
return api.passwordReset(email).success
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.openedx.auth.domain.interactor

import org.openedx.auth.data.model.LoginType
import org.openedx.auth.data.model.ValidationFields
import org.openedx.auth.data.repository.AuthRepository
import org.openedx.core.domain.model.RegistrationField
Expand All @@ -13,6 +14,10 @@ class AuthInteractor(private val repository: AuthRepository) {
repository.login(username, password)
}

suspend fun loginSocial(token: String?, loginType: LoginType) {
repository.socialLogin(token, loginType)
}

suspend fun getRegistrationFields(): List<RegistrationField> {
return repository.getRegistrationFields()
}
Expand Down
Loading

0 comments on commit bfb58db

Please sign in to comment.