Skip to content

Commit

Permalink
Better support for querying suspended accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
mattbdean committed May 26, 2018
1 parent b675eaa commit 54dda0e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 5 deletions.
27 changes: 27 additions & 0 deletions lib/src/main/java/net/dean/jraw/models/AccountQuery.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.dean.jraw.models;

import com.google.auto.value.AutoValue;
import org.jetbrains.annotations.Nullable;

/**
* The main function of an AccountQuery is to store the status of an account. If an account exists and is not suspended,
* then the {@link Account} object can be used normally.
*/
@AutoValue
public abstract class AccountQuery {
/** The reddit username being queried */
public abstract String getName();

public abstract AccountStatus getStatus();

/** The account data. Only non-null when the status is {@link AccountStatus#EXISTS}. */
@Nullable public abstract Account getAccount();

public static AccountQuery create(String name, AccountStatus status) {
return create(name, status, null);
}

public static AccountQuery create(String name, AccountStatus status, @Nullable Account data) {
return new AutoValue_AccountQuery(name, status, data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.dean.jraw

/**
* Thrown when directly querying a user who is suspended
*/
class SuspendedAccountException(val name: String, cause: Throwable? = null) :
Exception("Account '$name' is suspended", cause)
12 changes: 12 additions & 0 deletions lib/src/main/kotlin/net/dean/jraw/models/AccountStatus.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.dean.jraw.models

enum class AccountStatus {
/** The account exists and is not suspended */
EXISTS,

/** An account by the requested name has never been created */
NON_EXISTENT,

/** The account exists and has been suspended reddit-wide */
SUSPENDED
}
31 changes: 28 additions & 3 deletions lib/src/main/kotlin/net/dean/jraw/references/UserReferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.squareup.moshi.Types
import net.dean.jraw.*
import net.dean.jraw.JrawUtils.urlEncode
import net.dean.jraw.databind.Enveloped
import net.dean.jraw.http.NetworkException
import net.dean.jraw.models.*
import net.dean.jraw.models.internal.GenericJsonResponse
import net.dean.jraw.models.internal.RedditModelEnvelope
Expand All @@ -23,8 +24,11 @@ sealed class UserReference<out T : UserFlairReference>(reddit: RedditClient, val
/** True if and only if this UserReference is a [SelfUserReference] */
abstract val isSelf: Boolean

/** Fetches basic information about this user */
@EndpointImplementation(Endpoint.GET_ME, Endpoint.GET_USER_USERNAME_ABOUT)
/**
* Fetches basic information about this user.
*/
@Throws(SuspendedAccountException::class)
@Deprecated("Prefer query() for better handling of non-existent/suspended accounts", ReplaceWith("query()"))
fun about(): Account {
val body = reddit.request {
it.path(if (isSelf) "/api/v1/me" else "/user/$username/about")
Expand All @@ -33,7 +37,28 @@ sealed class UserReference<out T : UserFlairReference>(reddit: RedditClient, val
// /api/v1/me returns an Account that isn't wrapped with the data/kind nodes
if (isSelf)
return JrawUtils.adapter<Account>().fromJson(body)!!
return JrawUtils.adapter<Account>(Enveloped::class.java).fromJson(body)!!
try {
return JrawUtils.adapter<Account>(Enveloped::class.java).fromJson(body)!!
} catch (npe: NullPointerException) {
throw SuspendedAccountException(username)
}
}

/**
* Gets information about this account.
*/
@EndpointImplementation(Endpoint.GET_ME, Endpoint.GET_USER_USERNAME_ABOUT)
fun query(): AccountQuery {
return try {
AccountQuery.create(username, AccountStatus.EXISTS, about())
} catch (e: ApiException) {
if (e.cause is NetworkException && e.cause.res.code != 404)
throw e
else
AccountQuery.create(username, AccountStatus.NON_EXISTENT)
} catch (e: SuspendedAccountException) {
AccountQuery.create(username, AccountStatus.SUSPENDED)
}
}

/** Fetches any trophies the user has achieved */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package net.dean.jraw.test.integration

import com.winterbe.expekt.should
import net.dean.jraw.ApiException
import net.dean.jraw.models.AccountStatus
import net.dean.jraw.models.MultiredditPatch
import net.dean.jraw.models.UserHistorySort
import net.dean.jraw.models.TimePeriod
import net.dean.jraw.models.UserHistorySort
import net.dean.jraw.references.UserReference
import net.dean.jraw.test.CredentialsUtil
import net.dean.jraw.test.TestConfig.reddit
Expand All @@ -27,6 +28,30 @@ class UserReferenceTest : Spek({
}
}

describe("query") {
it("should return a status of EXISTS on an account that exists") {
val query = reddit.me().query()
query.name.should.equal(reddit.requireAuthenticatedUser())
query.account.should.not.be.`null`
query.status.should.equal(AccountStatus.EXISTS)
}

it("should return a status of NON_EXISTENT on an account name that has never been used") {
val name = randomName()
val query = reddit.user(name).query()
query.name.should.equal(name)
query.account.should.be.`null`
query.status.should.equal(AccountStatus.NON_EXISTENT)
}

it("should return a status of SUSPENDED on a suspended account") {
val query = reddit.user("TheFlintASteel").query()
query.name.should.equal("TheFlintASteel")
query.account.should.be.`null`
query.status.should.equal(AccountStatus.SUSPENDED)
}
}

describe("trophies") {
it("should return a List of Trophies") {
// Just make sure it deserializes
Expand Down
2 changes: 1 addition & 1 deletion lib/src/test/kotlin/net/dean/jraw/test/util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fun OAuthData.withExpiration(d: Date) = OAuthData.create(accessToken, scopes, re

val rand = SecureRandom()
fun randomName(length: Int = 10): String {
return "jraw_test_" + BigInteger(130, rand).toString(32).substring(0..length - 1)
return "jraw_test_" + BigInteger(130, rand).toString(32).substring(0 until length)
}

fun <T> expectDescendingScore(objects: List<T>, allowedMistakes: Int = 0) {
Expand Down

0 comments on commit 54dda0e

Please sign in to comment.