Skip to content

Commit

Permalink
NTV-530: ApiOperator.java crash (#1608)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkariang committed Apr 18, 2022
1 parent 2ab183c commit 72229be
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 144 deletions.
Expand Up @@ -5,7 +5,6 @@
import com.kickstarter.services.ResponseException;
import com.kickstarter.services.apiresponses.ErrorEnvelope;

import java.io.IOException;

import androidx.annotation.NonNull;
import retrofit2.Response;
Expand Down Expand Up @@ -53,13 +52,25 @@ public void onNext(final @NonNull retrofit2.Response<T> response) {
return;
}

if (response == null) {
subscriber.onError(new ResponseException(response));
return;
}

if (!response.isSuccessful()) {
try {
final ErrorEnvelope envelope = gson.fromJson(response.errorBody().string(), ErrorEnvelope.class);
subscriber.onError(new ApiException(envelope, response));
} catch (final @NonNull IOException e) {
subscriber.onError(new ResponseException(response));
}
ErrorEnvelope envelope;
try {
envelope = gson.fromJson(response.errorBody().string(), ErrorEnvelope.class);
} catch (final @NonNull Exception e) {
envelope = null;
}

if (envelope != null) {
subscriber.onError(new ApiException(envelope, response));
} else {
subscriber.onError(new ResponseException(response));
}

} else {
subscriber.onNext(response.body());
subscriber.onCompleted();
Expand Down

This file was deleted.

@@ -0,0 +1,166 @@
package com.kickstarter.services.apiresponses

import android.os.Parcelable
import androidx.annotation.StringDef
import com.kickstarter.services.ApiException
import kotlinx.parcelize.Parcelize
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy

@Parcelize
class ErrorEnvelope private constructor(
private val errorMessages: List<String>? = null,
private val httpCode: Int = 0,
private val ksrCode: String? = null,
private val facebookUser: FacebookUser? = null
) : Parcelable {
fun errorMessages() = this.errorMessages
fun httpCode() = this.httpCode
fun ksrCode() = this.ksrCode
fun facebookUser() = this.facebookUser

@Parcelize
class FacebookUser private constructor(
private val id: Long = 0L,
private val name: String? = null,
private val email: String? = null
) : Parcelable {
fun id() = this.id
fun name() = this.name
fun email() = this.email

@Parcelize
data class Builder(
private var id: Long = 0L,
private var name: String? = null,
private var email: String? = null
) : Parcelable {
fun id(id: Long?) = apply { this.id = id ?: 0L }
fun name(name: String?) = apply { this.name = name }
fun email(email: String?) = apply { this.email = email }
fun build() = FacebookUser(
id = id,
name = name,
email = email
)
}

fun toBuilder() = Builder(
id = id,
name = name,
email = email
)

override fun equals(other: Any?): Boolean {
var equals = super.equals(other)
if (other is FacebookUser) {
equals = id() == other.id() &&
name() == other.name() &&
email() == other.email()
}
return equals
}

companion object {
@JvmStatic
fun builder(): Builder {
return Builder()
}
}
}

data class Builder(
private var errorMessages: List<String>? = null,
private var httpCode: Int = 0,
private var ksrCode: String? = null,
private var facebookUser: FacebookUser? = null
) {
fun errorMessages(errorMessages: List<String?>?) = apply { this.errorMessages = errorMessages?.filterNotNull() }
fun httpCode(httpCode: Int?) = apply { this.httpCode = httpCode ?: 0 }
fun ksrCode(ksrCode: String?) = apply { this.ksrCode = ksrCode }
fun facebookUser(facebookUser: FacebookUser?) = apply { this.facebookUser = facebookUser }
fun build() = ErrorEnvelope(
errorMessages = errorMessages,
httpCode = httpCode,
ksrCode = ksrCode,
facebookUser = facebookUser
)
}

fun toBuilder() = Builder(
errorMessages = errorMessages,
httpCode = httpCode,
ksrCode = ksrCode,
facebookUser = facebookUser
)

@StringDef(INVALID_XAUTH_LOGIN, TFA_FAILED, TFA_REQUIRED)
@Retention(RetentionPolicy.SOURCE)
annotation class ErrorCode

val isConfirmFacebookSignupError: Boolean
get() = CONFIRM_FACEBOOK_SIGNUP == ksrCode()
val isInvalidLoginError: Boolean
get() = INVALID_XAUTH_LOGIN == ksrCode()
val isTfaRequiredError: Boolean
get() = TFA_REQUIRED == ksrCode()
val isTfaFailedError: Boolean
get() = TFA_FAILED == ksrCode()
val isMissingFacebookEmailError: Boolean
get() = MISSING_FACEBOOK_EMAIL == ksrCode()
val isFacebookInvalidAccessTokenError: Boolean
get() = FACEBOOK_INVALID_ACCESS_TOKEN == ksrCode()
val isUnauthorizedError: Boolean
get() = UNAUTHORIZED == ksrCode()

/*
When logging in the only two possible errors are INVALID_XAUTH_LOGIN
and TFA_REQUIRED, so we consider anything else an unknown error.
*/
val isGenericLoginError: Boolean
get() = INVALID_XAUTH_LOGIN != ksrCode() &&
TFA_REQUIRED != ksrCode()

/**
* Returns the first error message available, or `null` if there are none.
*/
fun errorMessage(): String? = errorMessages()?.firstOrNull()

override fun equals(other: Any?): Boolean {
var equals = super.equals(other)
if (other is ErrorEnvelope) {
equals = errorMessages() == other.errorMessages() &&
httpCode() == other.httpCode() &&
ksrCode() == other.ksrCode() &&
facebookUser() == other.facebookUser()
}
return equals
}

companion object {
@JvmStatic
fun builder(): Builder {
return Builder()
}

const val CONFIRM_FACEBOOK_SIGNUP = "confirm_facebook_signup"
const val INVALID_XAUTH_LOGIN = "invalid_xauth_login"
const val TFA_FAILED = "tfa_failed"
const val TFA_REQUIRED = "tfa_required"
const val MISSING_FACEBOOK_EMAIL = "missing_facebook_email"
const val FACEBOOK_INVALID_ACCESS_TOKEN = "facebook_invalid_access_token"
const val UNAUTHORIZED = "unauthorized"

/**
* Tries to extract an [ErrorEnvelope] from an exception, and if it
* can't returns null.
*/
@JvmStatic
fun fromThrowable(t: Throwable): ErrorEnvelope? {
if (t is ApiException) {
return t.errorEnvelope()
}
return null
}
}
}

0 comments on commit 72229be

Please sign in to comment.