Skip to content

Commit

Permalink
MBL-1170: Get token and User, Log in flow completed. (#1954)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkariang committed Feb 22, 2024
1 parent 81d14a6 commit bb46ce7
Show file tree
Hide file tree
Showing 17 changed files with 474 additions and 28 deletions.
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
android:theme="@style/Login" />
<activity
android:name=".ui.activities.OAuthActivity"
android:launchMode="singleTop"
android:launchMode="singleInstancePerTask"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/kickstarter/ApplicationModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ static Retrofit provideApiRetrofitV2(final @NonNull ApiEndpoint apiEndpoint,
@Singleton
@NonNull
static ApiRequestInterceptor provideApiRequestInterceptor(
final @NonNull String clientId, final @NonNull CurrentUserType currentUser,
final @NonNull String clientId, final @NonNull CurrentUserTypeV2 currentUser,
final @NonNull ApiEndpoint endpoint, final @NonNull PerimeterXClientType manager,
final @NonNull Build build) {
return new ApiRequestInterceptor(clientId, currentUser, endpoint.url(), manager, build);
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/com/kickstarter/mock/services/MockApiClientV2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.kickstarter.services.apiresponses.EmailVerificationEnvelope
import com.kickstarter.services.apiresponses.EmailVerificationEnvelope.Companion.builder
import com.kickstarter.services.apiresponses.MessageThreadEnvelope
import com.kickstarter.services.apiresponses.MessageThreadsEnvelope
import com.kickstarter.services.apiresponses.OAuthTokenEnvelope
import com.kickstarter.services.apiresponses.ProjectStatsEnvelope
import com.kickstarter.services.apiresponses.ProjectsEnvelope
import com.kickstarter.services.apiresponses.ShippingRulesEnvelope
Expand Down Expand Up @@ -287,10 +288,25 @@ open class MockApiClientV2 : ApiClientTypeV2 {
return Observable.empty()
}

override fun fetchCurrentUser(token: String): Observable<User> {
return Observable.empty()
}

override fun fetchLocation(param: String): Observable<Location> {
return Observable.just(sydney())
}

override fun loginWithCodes(
codeVerifier: String,
code: String,
clientId: String
): Observable<OAuthTokenEnvelope> {
return Observable.just(
OAuthTokenEnvelope.builder()
.accessToken("deadbeef")
.build()
)
}
override fun login(email: String, password: String): Observable<AccessTokenEnvelope> {
return Observable.just(
AccessTokenEnvelope.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.kickstarter.services.apiresponses.EmailVerificationEnvelope;
import com.kickstarter.services.apiresponses.MessageThreadEnvelope;
import com.kickstarter.services.apiresponses.MessageThreadsEnvelope;
import com.kickstarter.services.apiresponses.OAuthTokenEnvelope;
import com.kickstarter.services.apiresponses.ProjectStatsEnvelope;
import com.kickstarter.services.apiresponses.ProjectsEnvelope;
import com.kickstarter.services.apiresponses.ShippingRulesEnvelope;
Expand Down Expand Up @@ -52,6 +53,8 @@ public interface ApiClientTypeV2 {

@NonNull Observable<User> fetchCurrentUser();

@NonNull Observable<User> fetchCurrentUser(final @NonNull String token);

@NonNull Observable<Location> fetchLocation(final @NonNull String param);

@NonNull Observable<List<ProjectNotification>> fetchProjectNotifications();
Expand Down Expand Up @@ -94,6 +97,7 @@ public interface ApiClientTypeV2 {

@NonNull Observable<AccessTokenEnvelope> loginWithFacebook(final @NonNull String fbAccessToken, final @NonNull String code);

@NonNull Observable<OAuthTokenEnvelope> loginWithCodes(final @NonNull String codeVerifier, final @NonNull String code, final @NonNull String clientId);
@NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password);

@NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password, final @NonNull String code);
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/java/com/kickstarter/services/ApiClientV2.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.kickstarter.services.apirequests.BackingBody;
import com.kickstarter.services.apirequests.LoginWithFacebookBody;
import com.kickstarter.services.apirequests.MessageBody;
import com.kickstarter.services.apirequests.PKCEBody;
import com.kickstarter.services.apirequests.ProjectNotificationBody;
import com.kickstarter.services.apirequests.PushTokenBody;
import com.kickstarter.services.apirequests.RegisterWithFacebookBody;
Expand All @@ -39,6 +40,7 @@
import com.kickstarter.services.apiresponses.EmailVerificationEnvelope;
import com.kickstarter.services.apiresponses.MessageThreadEnvelope;
import com.kickstarter.services.apiresponses.MessageThreadsEnvelope;
import com.kickstarter.services.apiresponses.OAuthTokenEnvelope;
import com.kickstarter.services.apiresponses.ProjectStatsEnvelope;
import com.kickstarter.services.apiresponses.ProjectsEnvelope;
import com.kickstarter.services.apiresponses.ShippingRulesEnvelope;
Expand Down Expand Up @@ -132,6 +134,14 @@ public ApiClientV2(final @NonNull ApiServiceV2 service, final @NonNull Gson gson
.subscribeOn(Schedulers.io());
}

@Override
public @NonNull Observable<User> fetchCurrentUser(final @NonNull String token) {
return this.service
.currentUser(token)
.lift(apiErrorOperator())
.subscribeOn(Schedulers.io());
}

@Override
public @NonNull Observable<Location> fetchLocation(final @NonNull String param) {
return this.service.location(param)
Expand Down Expand Up @@ -318,6 +328,18 @@ public ApiClientV2(final @NonNull ApiServiceV2 service, final @NonNull Gson gson
.subscribeOn(Schedulers.io());
}

@Override
public @NonNull Observable<OAuthTokenEnvelope> loginWithCodes(final @NonNull String codeVerifier, final @NonNull String code, final @NonNull String clientId) {
return this.service
.login(PKCEBody.builder()
.code(code)
.codeVerifier(codeVerifier)
.clientId(clientId)
.build())
.lift(apiErrorOperator())
.subscribeOn(Schedulers.io());
}

@Override
public @NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password) {
return this.service
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/kickstarter/services/ApiServiceV2.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.kickstarter.services.apirequests.BackingBody;
import com.kickstarter.services.apirequests.LoginWithFacebookBody;
import com.kickstarter.services.apirequests.MessageBody;
import com.kickstarter.services.apirequests.PKCEBody;
import com.kickstarter.services.apirequests.ProjectNotificationBody;
import com.kickstarter.services.apirequests.PushTokenBody;
import com.kickstarter.services.apirequests.RegisterWithFacebookBody;
Expand All @@ -32,6 +33,7 @@
import com.kickstarter.services.apiresponses.EmailVerificationEnvelope;
import com.kickstarter.services.apiresponses.MessageThreadEnvelope;
import com.kickstarter.services.apiresponses.MessageThreadsEnvelope;
import com.kickstarter.services.apiresponses.OAuthTokenEnvelope;
import com.kickstarter.services.apiresponses.ProjectStatsEnvelope;
import com.kickstarter.services.apiresponses.ProjectsEnvelope;
import com.kickstarter.services.apiresponses.ShippingRulesEnvelope;
Expand Down Expand Up @@ -73,9 +75,15 @@ Observable<Response<ActivityEnvelope>> activities(@NonNull @Query("categories[]"
@GET("/v1/users/self")
Observable<Response<User>> currentUser();

@GET("/v1/users/self")
Observable<Response<User>> currentUser(@Query("oauth_token") String token);

@GET("/v1/locations/{param}")
Observable<Response<Location>> location(@Path("param") String param);

@POST("/v1/oauth/authorizations/exchange")
Observable<Response<OAuthTokenEnvelope>> login(@Body PKCEBody body);

@POST("/xauth/access_token")
Observable<Response<AccessTokenEnvelope>> login(@Body XauthBody body);

Expand Down
59 changes: 59 additions & 0 deletions app/src/main/java/com/kickstarter/services/apirequests/PKCEBody.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.kickstarter.services.apirequests

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
class PKCEBody private constructor(
private val code: String,
private val code_verifier: String,
private val client_id: String
) : Parcelable {

fun code() = this.code
fun codeVerifier() = this.code_verifier

@Parcelize
data class Builder(
private var code: String = "",
private var codeVerifier: String = "",
private var clientId: String = ""
) : Parcelable {
fun codeVerifier(codeVerifier: String) = apply { this.codeVerifier = codeVerifier }
fun code(code: String) = apply { this.code = code }

fun clientId(clientId: String) = apply { this.clientId = clientId }
fun build() = PKCEBody(
code_verifier = codeVerifier,
code = code,
client_id = clientId
)
}

fun toBuilder() = Builder(
codeVerifier = code_verifier,
code = code,
clientId = client_id
)

override fun equals(obj: Any?): Boolean {
var equals = super.equals(obj)
if (obj is PKCEBody) {
equals = code_verifier == obj.code_verifier &&
code == obj.code &&
client_id == obj.client_id
}
return equals
}

override fun hashCode(): Int {
var result = code.hashCode()
result = 31 * result + code_verifier.hashCode()
result = 31 * result + client_id.hashCode()
return result
}

companion object {
@JvmStatic
fun builder() = Builder()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.kickstarter.services.apirequests

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
class UserTokenBody private constructor(
private val oauth_token: String?
) : Parcelable {
fun token() = this.oauth_token

@Parcelize
data class Builder(
private var pushServer: String? = null,
private var token: String? = null
) : Parcelable {
fun token(token: String?) = apply { this.token = token }
fun build() = UserTokenBody(
oauth_token = token
)
}

fun toBuilder() = Builder(
token = oauth_token
)

companion object {
@JvmStatic
fun builder() = Builder()
}

override fun equals(other: Any?): Boolean {
var equals = super.equals(other)
if (other is UserTokenBody) {
equals =
token() == other.token()
}
return equals
}

override fun hashCode(): Int {
return oauth_token?.hashCode() ?: 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.kickstarter.services.apiresponses

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
class OAuthTokenEnvelope private constructor(
private val token: String,
) : Parcelable {
fun accessToken() = this.token

@Parcelize
data class Builder(
private var token: String = "",
) : Parcelable {
fun accessToken(accessToken: String) = apply { this.token = accessToken }
fun build() = OAuthTokenEnvelope(
token = token
)
}

override fun equals(obj: Any?): Boolean {
var equals = super.equals(obj)
if (obj is OAuthTokenEnvelope) {
equals = accessToken() == obj.accessToken()
}
return equals
}

fun toBuilder() = Builder(
token = token
)

override fun hashCode(): Int {
return token.hashCode()
}

companion object {
@JvmStatic
fun builder() = Builder()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.kickstarter.services.interceptors

import android.net.Uri
import com.kickstarter.libs.Build
import com.kickstarter.libs.CurrentUserType
import com.kickstarter.libs.CurrentUserTypeV2
import com.kickstarter.libs.FirebaseHelper
import com.kickstarter.libs.perimeterx.PerimeterXClientType
import com.kickstarter.libs.utils.WebUtils.userAgent
Expand All @@ -17,7 +17,7 @@ import java.io.IOException

class ApiRequestInterceptor(
private val clientId: String,
private val currentUser: CurrentUserType,
private val currentUser: CurrentUserTypeV2,
private val endpoint: String,
private val pxManager: PerimeterXClientType,
private val build: Build
Expand Down Expand Up @@ -52,11 +52,12 @@ class ApiRequestInterceptor(
val builder: Builder = initialHttpUrl.newBuilder()
.setQueryParameter("client_id", clientId)
currentUser.observable()
.filter { it.isPresent() }
.subscribe {
if (currentUser.accessToken != null) {
builder.setQueryParameter("oauth_token", currentUser.accessToken)
}
}
}.dispose()
return builder.build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ class LoginToutActivity : ComponentActivity() {
startResetActivity()
}
.addToDisposable(disposables)

viewModel.outputs.finishOauthWithSuccessfulResult()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { finishWithSuccessfulResult() }
.addToDisposable(disposables)
}

private fun facebookLoginClick() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.browser.customtabs.CustomTabsIntent
import androidx.lifecycle.lifecycleScope
import com.kickstarter.libs.utils.TransitionUtils
import com.kickstarter.libs.utils.extensions.getEnvironment
import com.kickstarter.libs.utils.extensions.isNotNull
import com.kickstarter.models.chrome.ChromeTabsHelperActivity
import com.kickstarter.ui.IntentKey
import com.kickstarter.ui.extensions.setUpConnectivityStatusCheck
Expand Down Expand Up @@ -46,8 +47,9 @@ class OAuthActivity : AppCompatActivity() {
openChromeTabWithUrl(state.authorizationUrl)
}

if (state.isTokenRetrieveStep && state.code.isNotEmpty()) {
// TODO WIP PHASE 3, VM call the endpoint with code & code_challenge, retrieve the token.
if (state.user.isNotNull()) {
setResult(RESULT_OK)
this@OAuthActivity.finish()
}
}
}
Expand All @@ -69,7 +71,7 @@ class OAuthActivity : AppCompatActivity() {

// BindCustomTabsService, obtain CustomTabsClient and Client, listens to navigation events
helper = ChromeTabsHelperActivity.CustomTabSessionAndClientHelper(this, authorizationUri) {
finish()
// finish()
}

// - Fallback in case Chrome is not installed, open WebViewActivity
Expand Down

0 comments on commit bb46ce7

Please sign in to comment.