add com.github.jreddit:1.0.4 package
parent
3f65168b94
commit
4b47d907cd
@ -0,0 +1,370 @@
|
||||
package com.github.jreddit.oauth;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
import org.apache.oltu.oauth2.client.OAuthClient;
|
||||
import org.apache.oltu.oauth2.client.URLConnectionClient;
|
||||
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
|
||||
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
|
||||
import org.apache.oltu.oauth2.common.OAuthProviderType;
|
||||
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
|
||||
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
|
||||
import org.apache.oltu.oauth2.common.message.types.GrantType;
|
||||
|
||||
import com.github.jreddit.oauth.app.RedditApp;
|
||||
import com.github.jreddit.oauth.exception.RedditOAuthException;
|
||||
import com.github.jreddit.oauth.param.RedditDuration;
|
||||
import com.github.jreddit.oauth.param.RedditScopeBuilder;
|
||||
import com.github.jreddit.request.util.KeyValueFormatter;
|
||||
|
||||
/**
|
||||
* Thread-safe reddit OAuth agent.<br>
|
||||
* <br>
|
||||
* Communicates with reddit to retrieve tokens, and converts them
|
||||
* into {@link RedditToken}s, which are used internally by jReddit. This class
|
||||
* supports both the <i>code grant flow</i> and <i>implicit grant flow</i>.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class RedditOAuthAgent {
|
||||
|
||||
/** Reddit authorization endpoint. */
|
||||
private static final String REDDIT_AUTHORIZE = "https://www.reddit.com/api/v1/authorize?";
|
||||
|
||||
/** Grant type for an installed client (weirdly enough a URI). */
|
||||
private static final String GRANT_TYPE_INSTALLED_CLIENT = "https://oauth.reddit.com/grants/installed_client";
|
||||
|
||||
/** Grant type for client credentials (described in OAuth2 standard). */
|
||||
private static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
|
||||
|
||||
/* Parameter keys */
|
||||
private static final String PARAM_CLIENT_ID = "client_id";
|
||||
private static final String PARAM_RESPONSE_TYPE = "response_type";
|
||||
private static final String PARAM_STATE = "state";
|
||||
private static final String PARAM_REDIRECT_URI = "redirect_uri";
|
||||
private static final String PARAM_DURATION = "duration";
|
||||
private static final String PARAM_SCOPE = "scope";
|
||||
private static final String PARAM_GRANT_TYPE = "grant_type";
|
||||
private static final String PARAM_CODE = "code";
|
||||
private static final String PARAM_DEVICE_ID = "device_id";
|
||||
|
||||
/* Header keys */
|
||||
private static final String HEADER_USER_AGENT = "User-Agent";
|
||||
private static final String HEADER_AUTHORIZATION = "Authorization";
|
||||
|
||||
/** User agent. */
|
||||
private final String userAgent;
|
||||
|
||||
/** OAuth2 client for OAuth related requests. */
|
||||
private OAuthClient oAuthClient;
|
||||
|
||||
/** Reddit application. */
|
||||
private RedditApp redditApp;
|
||||
|
||||
/**
|
||||
* Constructor for a Reddit OAuth agent.<br>
|
||||
* <br>
|
||||
* A default Apache OAuthClient will be made to perform the OAuth communication.
|
||||
*
|
||||
* @param userAgent User agent for your application (e.g. "jReddit: Reddit API Wrapper for Java")
|
||||
* @param redditApp Reddit application
|
||||
*/
|
||||
public RedditOAuthAgent(String userAgent, RedditApp redditApp) {
|
||||
this(userAgent, redditApp, new OAuthClient(new URLConnectionClient()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a Reddit OAuth agent.
|
||||
*
|
||||
* @param userAgent User agent for your application (e.g. "jReddit: Reddit API Wrapper for Java")
|
||||
* @param redditApp Reddit application
|
||||
* @param oAuthClient Apache OAuth2 client
|
||||
*/
|
||||
public RedditOAuthAgent(String userAgent, RedditApp redditApp, OAuthClient oAuthClient) {
|
||||
this.userAgent = userAgent;
|
||||
this.redditApp = redditApp;
|
||||
this.oAuthClient = oAuthClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the <i>code flow</i> Uniform Resource Locator (URI) for a
|
||||
* reddit user to authorize your application.<br>
|
||||
* <br>
|
||||
* The user will, after authorization, receive a <i>code</i>. This can be turned into
|
||||
* a <i>RedditToken</i> using {@link #token(String)}.
|
||||
*
|
||||
* @param scopeBuilder Authorization scope builder (must not be <i>null</i>)
|
||||
* @param duration Duration that the token can last
|
||||
*
|
||||
* @return The URI users need to visit and retrieve the <i>code</i> from
|
||||
*
|
||||
* @see {@link #token(String)} for converting the <i>code</i> into a usable <i>RedditToken</i>
|
||||
*/
|
||||
public synchronized String generateCodeFlowURI(RedditScopeBuilder scopeBuilder, RedditDuration duration) {
|
||||
|
||||
// Set parameters
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put(PARAM_CLIENT_ID, redditApp.getClientID());
|
||||
params.put(PARAM_RESPONSE_TYPE, "code");
|
||||
params.put(PARAM_STATE, UUID.randomUUID().toString());
|
||||
params.put(PARAM_REDIRECT_URI, redditApp.getRedirectURI());
|
||||
params.put(PARAM_DURATION, duration.value());
|
||||
params.put(PARAM_SCOPE, scopeBuilder.build());
|
||||
|
||||
// Create URI
|
||||
return REDDIT_AUTHORIZE + KeyValueFormatter.format(params, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the <i>implicit flow</i> Uniform Resource Locator (URI) for a
|
||||
* reddit user to authorize your application.<br>
|
||||
* <br>
|
||||
* The user will, after authorization, receive token information. This can be turned into
|
||||
* a <i>RedditToken</i> using {@link #tokenFromInfo(String, String, long, String)}.
|
||||
*
|
||||
* @param scopeBuilder Authorization scope builder (must not be <i>null</i>)
|
||||
*
|
||||
* @return The URI users need to visit and retrieve the <i>token information</i> from
|
||||
*
|
||||
* @see {@link #tokenFromInfo(String, String, long, String)} for converting the
|
||||
* <i>token information</i> into <i>RedditToken</i>
|
||||
*/
|
||||
public synchronized String generateImplicitFlowURI(RedditScopeBuilder scopeBuilder) {
|
||||
|
||||
// Set parameters
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put(PARAM_CLIENT_ID, redditApp.getClientID());
|
||||
params.put(PARAM_RESPONSE_TYPE, "token");
|
||||
params.put(PARAM_STATE, UUID.randomUUID().toString());
|
||||
params.put(PARAM_REDIRECT_URI, redditApp.getRedirectURI());
|
||||
params.put(PARAM_SCOPE, scopeBuilder.build());
|
||||
|
||||
// Create URI
|
||||
return REDDIT_AUTHORIZE + KeyValueFormatter.format(params, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user agent to the OAuth request.
|
||||
*
|
||||
* @param request OAuth request
|
||||
*/
|
||||
private void addUserAgent(OAuthClientRequest request) {
|
||||
request.addHeader(HEADER_USER_AGENT, userAgent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the basic authentication protocol to the OAuth request using
|
||||
* the credentials of the Reddit application provided.
|
||||
*
|
||||
* @param request OAuth request
|
||||
* @param app Reddit application
|
||||
*/
|
||||
private void addBasicAuthentication(OAuthClientRequest request, RedditApp app) {
|
||||
String authString = app.getClientID() + ":" + app.getClientSecret();
|
||||
String authStringEnc = DatatypeConverter.printBase64Binary(authString.getBytes());
|
||||
request.addHeader(HEADER_AUTHORIZATION, "Basic " + authStringEnc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Token retrieval (<i>code</i> flow).<br>
|
||||
* <br>
|
||||
* Retrieve a token for a specific user, meaning that the token is <u>coupled to a user</u>.
|
||||
* After it has expired, the token will no longer work. You must either request a new
|
||||
* token, or refresh it using {@link #refreshToken(RedditToken)}.
|
||||
*
|
||||
* @param code One-time code received from the user, after manual authorization by that user
|
||||
*
|
||||
* @return Token (associated with a user)
|
||||
*
|
||||
* @throws RedditOAuthException
|
||||
*/
|
||||
public synchronized RedditToken token(String code) throws RedditOAuthException {
|
||||
|
||||
try {
|
||||
|
||||
// Set general values of the request
|
||||
OAuthClientRequest request = OAuthClientRequest
|
||||
.tokenProvider(OAuthProviderType.REDDIT)
|
||||
.setGrantType(GrantType.AUTHORIZATION_CODE)
|
||||
.setClientId(redditApp.getClientID())
|
||||
.setClientSecret(redditApp.getClientSecret())
|
||||
.setRedirectURI(redditApp.getRedirectURI())
|
||||
.setParameter(PARAM_CODE, code)
|
||||
.buildBodyMessage();
|
||||
|
||||
// Add the user agent
|
||||
addUserAgent(request);
|
||||
|
||||
// Add basic authentication
|
||||
addBasicAuthentication(request, redditApp);
|
||||
|
||||
// Return a wrapper controlled by jReddit
|
||||
return new RedditToken(oAuthClient.accessToken(request));
|
||||
|
||||
} catch (OAuthSystemException oase) {
|
||||
throw new RedditOAuthException(oase);
|
||||
} catch (OAuthProblemException oape) {
|
||||
throw new RedditOAuthException(oape);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh token.<br>
|
||||
* <br>
|
||||
* This is <u>only</u> possible for tokens retrieved through the <u>code flow</u>
|
||||
* authorization and had their duration set to permanent. Tokens that do not have
|
||||
* a refresh_token with them or are expired, will not be able to be refreshed.
|
||||
* In that case, a new one must be acquired.
|
||||
*
|
||||
* @param rToken Reddit token (which needs to be refreshed)
|
||||
*
|
||||
* @return Whether the token was successfully refreshed
|
||||
*
|
||||
* @throws RedditOAuthException
|
||||
*
|
||||
* @see RedditToken#isRefreshable()
|
||||
*/
|
||||
public synchronized boolean refreshToken(RedditToken rToken) throws RedditOAuthException {
|
||||
|
||||
try {
|
||||
|
||||
// Check whether the token can be refreshed
|
||||
if (rToken.isRefreshable()) {
|
||||
|
||||
// Set general values of the request
|
||||
OAuthClientRequest request = OAuthClientRequest
|
||||
.tokenProvider(OAuthProviderType.REDDIT)
|
||||
.setGrantType(GrantType.REFRESH_TOKEN)
|
||||
.setRefreshToken(rToken.getRefreshToken())
|
||||
.buildBodyMessage();
|
||||
|
||||
// Add the user agent
|
||||
addUserAgent(request);
|
||||
|
||||
// Add basic authentication
|
||||
addBasicAuthentication(request, redditApp);
|
||||
|
||||
// Return a wrapper controlled by jReddit
|
||||
rToken.refresh(oAuthClient.accessToken(request));
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
// The token cannot be refreshed
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (OAuthSystemException oase) {
|
||||
throw new RedditOAuthException(oase);
|
||||
} catch (OAuthProblemException oape) {
|
||||
throw new RedditOAuthException(oape);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Token retrieval (<i>app-only</i> flow).<br>
|
||||
* <br>
|
||||
* Retrieve a token for the <u>application-only</u>, meaning that the
|
||||
* token is <u>not coupled to any user</u>. The token is typically only
|
||||
* <u>valid for a short period of time</u> (at the moment of writing: 1 hour).
|
||||
* After it has expired, the token will no longer work. You must request a <u>new</u>
|
||||
* token in that case. Refreshing an application-only token is not possible.
|
||||
*
|
||||
* @param confidential <i>True</i>: confidential clients (web apps / scripts) not acting on
|
||||
* behalf of one or more logged out users. <i>False</i>: installed app types,
|
||||
* and other apps acting on behalf of one or more logged out users.
|
||||
*
|
||||
* @return Token (not associated with a user)
|
||||
*
|
||||
* @throws RedditOAuthException
|
||||
*/
|
||||
public synchronized RedditToken tokenAppOnly(boolean confidential) throws RedditOAuthException {
|
||||
|
||||
try {
|
||||
|
||||
// Set general values of the request
|
||||
TokenRequestBuilder builder = OAuthClientRequest
|
||||
.tokenProvider(OAuthProviderType.REDDIT)
|
||||
.setParameter(PARAM_GRANT_TYPE, confidential ? GRANT_TYPE_CLIENT_CREDENTIALS : GRANT_TYPE_INSTALLED_CLIENT)
|
||||
.setClientId(redditApp.getClientID())
|
||||
.setClientSecret(redditApp.getClientSecret());
|
||||
|
||||
// If it is not acting on behalf of a unique client, a unique device identifier must be generated:
|
||||
if (!confidential) {
|
||||
builder = builder.setParameter(PARAM_DEVICE_ID, UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
// Build the request
|
||||
OAuthClientRequest request = builder.buildBodyMessage();
|
||||
|
||||
// Add the user agent
|
||||
addUserAgent(request);
|
||||
|
||||
// Add basic authentication
|
||||
addBasicAuthentication(request, redditApp);
|
||||
|
||||
// Return a wrapper controlled by jReddit
|
||||
return new RedditToken(oAuthClient.accessToken(request));
|
||||
|
||||
} catch (OAuthSystemException oase) {
|
||||
throw new RedditOAuthException(oase);
|
||||
} catch (OAuthProblemException oape) {
|
||||
throw new RedditOAuthException(oape);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a token from information received using the <i>implicit grant flow</i>.<br>
|
||||
* <br>
|
||||
* <b>WARNING:</b> The expiration of the token is no longer very accurate. There is a delay
|
||||
* between the user receiving the token, and inputting it into this function. Beware that the
|
||||
* token might expire earlier than that the token reports it to.
|
||||
*
|
||||
* @param accessToken Access token
|
||||
* @param tokenType Token type (commonly "bearer")
|
||||
* @param expiresIn Expires in (seconds)
|
||||
* @param scope Scope
|
||||
*
|
||||
* @return <i>RedditToken</i> generated using the given information.
|
||||
*/
|
||||
public synchronized RedditToken tokenFromInfo(String accessToken, String tokenType, long expiresIn, String scope) {
|
||||
return new RedditToken(accessToken, tokenType, expiresIn, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revocation of a <i>RedditToken</i>.<br>
|
||||
* <br>
|
||||
* Be sure to not use the token after
|
||||
* calling this function, as its state pertaining its validity (e.g. scope,
|
||||
* expiration, refreshability) is no longer valid when it is revoked.<br>
|
||||
* <br>
|
||||
* <i>Note: Per RFC 7009, this request will return a success (204) response
|
||||
* even if the passed in token was never valid.</i>
|
||||
*
|
||||
* @param token <i>RedditToken</i> to revoke
|
||||
* @param revokeAccessTokenOnly Whether to only revoke the access token, or both
|
||||
*
|
||||
* @return Whether the token is no longer valid
|
||||
*/
|
||||
public boolean revoke(RedditToken token, boolean revokeAccessTokenOnly) {
|
||||
// TODO: Implement
|
||||
// https://www.reddit.com/api/v1/revoke_token
|
||||
// In POST data: token=TOKEN&token_type_hint=TOKEN_TYPE
|
||||
// TOKEN_TYPE: refresh_token or access_token
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
package com.github.jreddit.oauth;
|
||||
|
||||
import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
|
||||
|
||||
import com.github.jreddit.oauth.param.RedditScope;
|
||||
import com.github.jreddit.oauth.param.RedditTokenCompleteScope;
|
||||
|
||||
/**
|
||||
* OAuth2 token wrapper for reddit.<br>
|
||||
* <br>
|
||||
* This class wraps the information received from reddit following
|
||||
* the request for a token.<br>
|
||||
* A token has three dimensions:
|
||||
* <ul>
|
||||
* <li><b>scope:</b> what can it be used for?
|
||||
* <li><b>expiration:</b> how long can it be used?
|
||||
* <li><b>refreshable:</b> can its duration be prolonged?
|
||||
* </ul>
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*
|
||||
*/
|
||||
public class RedditToken {
|
||||
|
||||
/** Token type parameter. */
|
||||
public static final String PARAM_TOKEN_TYPE = "token_type";
|
||||
|
||||
/** Access token. */
|
||||
private String accessToken;
|
||||
|
||||
/** Refresh token. */
|
||||
private String refreshToken;
|
||||
|
||||
/** Manager of the scopes that this token applies to. */
|
||||
private RedditTokenCompleteScope scopes;
|
||||
|
||||
/** Token type. Only value possible (15-06-2015): bearer */
|
||||
private String tokenType;
|
||||
|
||||
/** Time at which the token expires (seconds since UNIX epoch). */
|
||||
private long expiration;
|
||||
|
||||
/** How long the token was valid starting from its creation (in seconds). */
|
||||
private long expirationSpan;
|
||||
|
||||
/**
|
||||
* @param token JSON response after an OAuth2 token request
|
||||
*/
|
||||
protected RedditToken(OAuthJSONAccessTokenResponse token) {
|
||||
this.accessToken = token.getAccessToken();
|
||||
this.refreshToken = token.getRefreshToken();
|
||||
this.expiration = currentTimeSeconds() + token.getExpiresIn();
|
||||
this.expirationSpan = token.getExpiresIn();
|
||||
this.scopes = new RedditTokenCompleteScope(token.getScope());
|
||||
this.tokenType = token.getParam(PARAM_TOKEN_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reddit token constructor with specific user-provided parameters.
|
||||
*
|
||||
* @param accessToken Access token
|
||||
* @param tokenType Type of token (commonly "bearer")
|
||||
* @param expiresIn Expires in (seconds)
|
||||
* @param scope Scope
|
||||
*/
|
||||
protected RedditToken(String accessToken, String tokenType, long expiresIn, String scope) {
|
||||
this.accessToken = accessToken;
|
||||
this.refreshToken = null;
|
||||
this.expiration = currentTimeSeconds() + expiresIn;
|
||||
this.expirationSpan = expiresIn;
|
||||
this.scopes = new RedditTokenCompleteScope(scope);
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh this reddit token with data received from the new token.
|
||||
*
|
||||
* @param token Token received from a refresh request to reddit
|
||||
*/
|
||||
public void refresh(OAuthJSONAccessTokenResponse token) {
|
||||
this.accessToken = token.getAccessToken();
|
||||
this.expiration = currentTimeSeconds() + token.getExpiresIn();
|
||||
this.expirationSpan = token.getExpiresIn();
|
||||
this.scopes = new RedditTokenCompleteScope(token.getScope());
|
||||
this.tokenType = token.getParam(PARAM_TOKEN_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the access token.
|
||||
*
|
||||
* @return Access token (e.g. "jsdkjfskaj9f8-dnafk")
|
||||
*/
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the refresh token.
|
||||
*
|
||||
* @return Refresh token (e.g. "nvkJu9kjdada2-d98afj")
|
||||
*/
|
||||
public String getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether the token is expired.
|
||||
*
|
||||
* @return Is the token expired?
|
||||
*/
|
||||
public boolean isExpired() {
|
||||
return expiration < currentTimeSeconds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this token possess this particular authorization scope.
|
||||
* If it does not support the scope, it means that the token does
|
||||
* not have approval from the user to perform the actions belonging to
|
||||
* that scope.
|
||||
*
|
||||
* @param scope Reddit scope
|
||||
*
|
||||
* @return Does this token support this scope?
|
||||
*/
|
||||
public boolean hasScope(RedditScope scope) {
|
||||
return this.scopes.has(scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the expiration.
|
||||
*
|
||||
* @return Expiration time (seconds since UNIX epoch)
|
||||
*/
|
||||
public long getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
/**
|
||||
* Retrieve the token type.
|
||||
*
|
||||
* @return Token type (e.g. "bearer")
|
||||
*/
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the token can be refreshed.
|
||||
* This means that a refresh token exists.
|
||||
*
|
||||
* @return Can the token be refreshed?
|
||||
*/
|
||||
public boolean isRefreshable() {
|
||||
return this.getRefreshToken() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this token will expire within the given time frame (given in seconds).
|
||||
*
|
||||
* @param seconds Amount of seconds
|
||||
*
|
||||
* @return Will the token expire within the given time frame?
|
||||
*/
|
||||
public boolean willExpireIn(long seconds) {
|
||||
return currentTimeSeconds() + seconds > expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the original expiration span of the token starting from its creation.
|
||||
*
|
||||
* @return Expiration span (in seconds)
|
||||
*/
|
||||
public long getExpirationSpan() {
|
||||
return expirationSpan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current time in seconds.
|
||||
*
|
||||
* Uses <i>System.currentTimeMillis()</i>.
|
||||
*
|
||||
* @return Current time in seconds.
|
||||
*/
|
||||
private static long currentTimeSeconds() {
|
||||
return System.currentTimeMillis() / (long) 1000;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.github.jreddit.oauth.app;
|
||||
|
||||
public abstract class RedditApp {
|
||||
|
||||
private final String clientID;
|
||||
private final String clientSecret;
|
||||
private final String redirectURI;
|
||||
|
||||
/**
|
||||
* Reddit Application.<br>
|
||||
* <br>
|
||||
* <i>All</i> information given in this constructor <i>must</i>
|
||||
* match the information stated on reddit.
|
||||
*
|
||||
* @param clientID Client identifier (e.g. "p_jcolKysdMFud")
|
||||
* @param clientSecret Client secret (e.g. "gko_LXEJKF89djs98fhFJkj9s")
|
||||
* @param redirectURI Redirect URI (e.g. "http://www.example.com/auth")
|
||||
*/
|
||||
public RedditApp(String clientID, String clientSecret, String redirectURI) {
|
||||
this.clientID = clientID;
|
||||
this.clientSecret = clientSecret;
|
||||
this.redirectURI = redirectURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve client identifier.
|
||||
*
|
||||
* @return Client identifier (e.g. "p_jcolKysdMFud")
|
||||
*/
|
||||
public String getClientID() {
|
||||
return clientID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve client secret.
|
||||
*
|
||||
* @return Client secret (e.g. "gko_LXEJKF89djs98fhFJkj9s")
|
||||
*/
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve redirect Uniform Resource Identifier.
|
||||
*
|
||||
* @return Redirect URI (e.g. "http://www.example.com/auth")
|
||||
*/
|
||||
public String getRedirectURI() {
|
||||
return redirectURI;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.github.jreddit.oauth.app;
|
||||
|
||||
public class RedditInstalledApp extends RedditApp {
|
||||
|
||||
/**
|
||||
* Reddit Installed Application.<br>
|
||||
* <br>
|
||||
* <i>All</i> information given in this constructor <i>must</i>
|
||||
* match the information stated on reddit. The secret is defaulted
|
||||
* to an empty string.
|
||||
*
|
||||
* @param clientID Client identifier (e.g. "p_jcolKysdMFud")
|
||||
* @param redirectURI Redirect URI (e.g. "http://www.example.com/auth")
|
||||
*/
|
||||
public RedditInstalledApp(String clientID, String redirectURI) {
|
||||
super(clientID, "", redirectURI); // Empty string is the secret for an installed app
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.github.jreddit.oauth.app;
|
||||
|
||||
public class RedditScriptApp extends RedditApp {
|
||||
|
||||
/**
|
||||
* Reddit Script Application.<br>
|
||||
* <br>
|
||||
* <i>All</i> information given in this constructor <i>must</i>
|
||||
* match the information stated on reddit.
|
||||
*
|
||||
* @param clientID Client identifier (e.g. "p_jcolKysdMFud")
|
||||
* @param clientSecret Client secret (e.g. "gko_LXEJKF89djs98fhFJkj9s")
|
||||
* @param redirectURI Redirect URI (e.g. "http://www.example.com/auth")
|
||||
*/
|
||||
public RedditScriptApp(String clientID, String clientSecret, String redirectURI) {
|
||||
super(clientID, clientSecret, redirectURI);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.github.jreddit.oauth.app;
|
||||
|
||||
public class RedditWebApp extends RedditApp {
|
||||
|
||||
/**
|
||||
* Reddit Web Application.<br>
|
||||
* <br>
|
||||
* <i>All</i> information given in this constructor <i>must</i>
|
||||
* match the information stated on reddit.
|
||||
*
|
||||
* @param clientID Client identifier (e.g. "p_jcolKysdMFud")
|
||||
* @param clientSecret Client secret (e.g. "gko_LXEJKF89djs98fhFJkj9s")
|
||||
* @param redirectURI Redirect URI (e.g. "http://www.example.com/auth")
|
||||
*/
|
||||
public RedditWebApp(String clientID, String clientSecret, String redirectURI) {
|
||||
super(clientID, clientSecret, redirectURI);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.github.jreddit.oauth.client;
|
||||
|
||||
import com.github.jreddit.oauth.RedditToken;
|
||||
import com.github.jreddit.request.RedditGetRequest;
|
||||
import com.github.jreddit.request.RedditPostRequest;
|
||||
|
||||
public abstract class RedditClient {
|
||||
|
||||
/** API Domain of OAuth */
|
||||
public static final String OAUTH_API_DOMAIN = "https://oauth.reddit.com";
|
||||
|
||||
/**
|
||||
* Perform a POST reddit request authenticated with the given reddit token.<br>
|
||||
* <br>
|
||||
* Does the following: (a) generates the URI (including query parameters) and appends
|
||||
* it to the reddit base, (b) adds the POST body parameters,
|
||||
* (c) adds the authorization from the token to the request, and
|
||||
* (d) executes the request.<br>
|
||||
* <br>
|
||||
* <i>Exception handling: if any function raises an exception,
|
||||
* it will be logged using SLF4J. The result would be null.</i>
|
||||
*
|
||||
* @param rToken Reddit token
|
||||
* @param request Reddit POST request
|
||||
*
|
||||
* @return Response from reddit (raw), if failed <i>null</i>
|
||||
*/
|
||||
public abstract String post(RedditToken rToken, RedditPostRequest request);
|
||||
|
||||
/**
|
||||
* Perform a GET reddit request authenticated with the given reddit token.<br>
|
||||
* <br>
|
||||
* Does the following: (a) generates the URI (including query parameters) and appends
|
||||
* it to the reddit base, (b) adds the authorization from the token to
|
||||
* the request, and (c) executes the request.<br>
|
||||
* <br>
|
||||
* <i>Exception handling: if any function raises an exception,
|
||||
* it will be logged using SLF4J. The result would be null.</i>
|
||||
*
|
||||
* @param rToken Reddit token
|
||||
* @param request Reddit GET request
|
||||
*
|
||||
* @return Response from reddit (raw), if failed <i>null</i>
|
||||
*/
|
||||
public abstract String get(RedditToken rToken, RedditGetRequest request);
|
||||
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package com.github.jreddit.oauth.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.oauth.RedditToken;
|
||||
import com.github.jreddit.request.RedditGetRequest;
|
||||
import com.github.jreddit.request.RedditPostRequest;
|
||||
|
||||
/**
|
||||
* HTTP client implementation for a <i>RedditClient</i>.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*
|
||||
* @see RedditClient
|
||||
*/
|
||||
public class RedditHttpClient extends RedditClient {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RedditHttpClient.class);
|
||||
|
||||
private final String userAgent;
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
/**
|
||||
* @param userAgent User agent of your application
|
||||
* @param httpClient HTTP client to use for the requests
|
||||
*/
|
||||
public RedditHttpClient(String userAgent, HttpClient httpClient) {
|
||||
this.userAgent = userAgent;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String post(RedditToken rToken, RedditPostRequest redditRequest) {
|
||||
|
||||
try {
|
||||
|
||||
// Create post request
|
||||
HttpPost request = new HttpPost(OAUTH_API_DOMAIN + redditRequest.generateRedditURI());
|
||||
|
||||
// Add parameters to body
|
||||
request.setEntity(new StringEntity(redditRequest.generateBody()));
|
||||
|
||||
// Add authorization
|
||||
addAuthorization(request, rToken);
|
||||
|
||||
// Add user agent
|
||||
addUserAgent(request);
|
||||
|
||||
// Add content type
|
||||
request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||
|
||||
return executeHttpRequest(request);
|
||||
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
LOGGER.warn("Unsupported Encoding Exception thrown in POST request when encoding body", uee);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(RedditToken rToken, RedditGetRequest redditRequest) {
|
||||
|
||||
// Create get request
|
||||
HttpGet request = new HttpGet(OAUTH_API_DOMAIN + redditRequest.generateRedditURI());
|
||||
|
||||
// Add authorization
|
||||
addAuthorization(request, rToken);
|
||||
|
||||
// Add user agent
|
||||
addUserAgent(request);
|
||||
|
||||
return executeHttpRequest(request);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given HTTP request.
|
||||
*
|
||||
* @param request HTTP request
|
||||
*
|
||||
* @return Result, <i>null</i> if failed
|
||||
*/
|
||||
private String executeHttpRequest(HttpUriRequest request) {
|
||||
try {
|
||||
|
||||
// Attempt to do execute request
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
|
||||
// Return response if successful
|
||||
if (response != null) {
|
||||
return EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||
}
|
||||
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
LOGGER.warn("Unsupported Encoding Exception thrown in request", uee);
|
||||
} catch (ClientProtocolException cpe) {
|
||||
LOGGER.warn("Client Protocol Exception thrown in request", cpe);
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("I/O Exception thrown in request", ioe);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add authorization to the HTTP request.
|
||||
*
|
||||
* @param request HTTP request
|
||||
* @param rToken Reddit token (generally of the "bearer" type)
|
||||
*/
|
||||
private void addAuthorization(HttpRequest request, RedditToken rToken) {
|
||||
request.addHeader("Authorization", rToken.getTokenType() + " " + rToken.getAccessToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user agent to the HTTP request.
|
||||
*
|
||||
* @param request HTTP request
|
||||
*/
|
||||
private void addUserAgent(HttpRequest request) {
|
||||
request.addHeader("User-Agent", userAgent);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.github.jreddit.oauth.client;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.oauth.RedditToken;
|
||||
import com.github.jreddit.request.RedditGetRequest;
|
||||
import com.github.jreddit.request.RedditPostRequest;
|
||||
|
||||
/**
|
||||
* Wrapper for any reddit client, which makes it <i>polite</i>.
|
||||
* Polite means that it will only send requests in an interval,
|
||||
* and does not overload reddit. It will also mean you will get
|
||||
* less denial messages from reddit *hint* *hint*.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class RedditPoliteClient extends RedditClient {
|
||||
|
||||
/** Logger for this class. */
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RedditPoliteClient.class);
|
||||
|
||||
/** Wrapped reddit client. */
|
||||
private RedditClient redditClient;
|
||||
|
||||
/** Default interval in milliseconds (1 per second). */
|
||||
private static final long DEFAULT_INTERVAL = 1000L;
|
||||
|
||||
/** Default interval in milliseconds. */
|
||||
private long interval;
|
||||
|
||||
/** Last time a request was made. */
|
||||
private long lastReqTime = 0;
|
||||
|
||||
/**
|
||||
* Polite wrapper around the reddit client.
|
||||
*
|
||||
* @param redditClient Reddit client to wrap
|
||||
*/
|
||||
public RedditPoliteClient(RedditClient redditClient) {
|
||||
this(redditClient, DEFAULT_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polite wrapper around the reddit client with configurable time.
|
||||
*
|
||||
* @param redditClient Reddit client to wrap
|
||||
* @param interval Interval in milliseconds
|
||||
*/
|
||||
public RedditPoliteClient(RedditClient redditClient, long interval) {
|
||||
this.redditClient = redditClient;
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String post(RedditToken rToken, RedditPostRequest request) {
|
||||
waitIfNeeded();
|
||||
String result = redditClient.post(rToken, request);
|
||||
noteTime();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(RedditToken rToken, RedditGetRequest request) {
|
||||
waitIfNeeded();
|
||||
String result = redditClient.get(rToken, request);
|
||||
noteTime();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note the current time.
|
||||
*/
|
||||
private void noteTime() {
|
||||
lastReqTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait if required.
|
||||
*/
|
||||
private void waitIfNeeded() {
|
||||
|
||||
// Calculate elapsed milliseconds
|
||||
long elapsed = System.currentTimeMillis() - lastReqTime;
|
||||
|
||||
// If enough time has elapsed, no need to wait
|
||||
if (elapsed >= interval) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If not enough time was elapsed, wait the remainder
|
||||
long toWait = interval - elapsed;
|
||||
try {
|
||||
Thread.sleep(toWait);
|
||||
} catch (InterruptedException ie) {
|
||||
LOGGER.warn("Interrupted Exception thrown while politely waiting for remainder of interval", ie);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.github.jreddit.oauth.exception;
|
||||
|
||||
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
|
||||
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
|
||||
|
||||
public class RedditOAuthException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 2403104136770312353L;
|
||||
|
||||
public RedditOAuthException(OAuthSystemException e) {
|
||||
super("A OAuth system exception was thrown when authenticating with reddit.", e);
|
||||
}
|
||||
|
||||
public RedditOAuthException(OAuthProblemException e) {
|
||||
super("A OAuth problem exception was thrown when authenticating with reddit.", e);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.github.jreddit.oauth.param;
|
||||
|
||||
/**
|
||||
* Enumerator for the duration of tokens.<br>
|
||||
* <br>
|
||||
* There are two possible values:
|
||||
* <ul>
|
||||
* <li><b>permanent:</b> The token can be refreshed as many times as the application desires.</li>
|
||||
* <li><b>temporary:</b> The token cannot be refreshed, and will last for <i>one hour</i>.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum RedditDuration {
|
||||
|
||||
PERMANENT("permanent"),
|
||||
TEMPORARY("temporary");
|
||||
|
||||
private final String value;
|
||||
|
||||
RedditDuration(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.github.jreddit.oauth.param;
|
||||
|
||||
/**
|
||||
* Enumerator for the possible authorization scopes for reddit requests.<br>
|
||||
* <br>
|
||||
* These scopes are used to specify what actions an application
|
||||
* can perform with the generated token. The scope can be combined
|
||||
* together, so that a single token can have access to multiple scopes.
|
||||
*
|
||||
* @see RedditScopeBuilder
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum RedditScope {
|
||||
|
||||
IDENTITY("identity"),
|
||||
EDIT("edit"),
|
||||
FLAIR("flair"),
|
||||
HISTORY("history"),
|
||||
MODCONFIG("modconfig"),
|
||||
MODFLAIR("modflair"),
|
||||
MODLOG("modlog"),
|
||||
MODPOSTS("modposts"),
|
||||
MODWIKI("modwiki"),
|
||||
MYSUBREDDITS("mysubreddits"),
|
||||
PRIVATEMESSAGE("privatemessages"),
|
||||
READ("read"),
|
||||
REPORT("report"),
|
||||
SAVE("save"),
|
||||
SUBMIT("submit"),
|
||||
SUBSCRIBE("subscribe"),
|
||||
VOTE("vote"),
|
||||
WIKIEDIT("wikiedit"),
|
||||
WIKIREAD("wikiread");
|
||||
|
||||
protected static final String SEPARATOR = ",";
|
||||
|
||||
private final String value;
|
||||
|
||||
RedditScope(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package com.github.jreddit.oauth.param;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Builder for the scopes of a request.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*
|
||||
*/
|
||||
public class RedditScopeBuilder {
|
||||
|
||||
/** Set of reddit scopes. */
|
||||
private Set<RedditScope> scopes;
|
||||
|
||||
public RedditScopeBuilder() {
|
||||
scopes = new HashSet<RedditScope>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a string for the request. Called upon by
|
||||
* <i>RedditToken</i> when requesting a token that
|
||||
* allows scope definition.
|
||||
*
|
||||
* @return String list of the scopes
|
||||
*/
|
||||
public String build() {
|
||||
|
||||
// Add each scope to the scope list
|
||||
String s = "";
|
||||
for (RedditScope scope : scopes) {
|
||||
s += scope.value() + RedditScope.SEPARATOR;
|
||||
}
|
||||
|
||||
// Remove final separator
|
||||
if (s.length() > 0) {
|
||||
s = s.substring(0, s.length() - RedditScope.SEPARATOR.length());
|
||||
}
|
||||
|
||||
// Return scope list
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a scope to the builder. If the scope has already
|
||||
* been added, it will not be added double.
|
||||
*
|
||||
* @param scope Reddit scope
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public RedditScopeBuilder addScope(RedditScope scope) {
|
||||
scopes.add(scope);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple scopes to the builder. If a scope has already
|
||||
* been added, it will not be added double.
|
||||
*
|
||||
* @param scopes Multiple scopes
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public RedditScopeBuilder addScopes(RedditScope... scopes) {
|
||||
for (RedditScope scope : scopes) {
|
||||
addScope(scope);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a scope from the builder.
|
||||
*
|
||||
* @param scope Reddit scope
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public RedditScopeBuilder removeScope(RedditScope scope) {
|
||||
scopes.remove(scope);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove multiple scopes from the builder.
|
||||
*
|
||||
* @param scopes Multiple scopes
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public RedditScopeBuilder removeScopes(RedditScope... scopes) {
|
||||
for (RedditScope scope : scopes) {
|
||||
removeScope(scope);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.github.jreddit.oauth.param;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Manager of the scopes a response from reddit returns.
|
||||
* Used by <i>RedditToken</i> to parse the list of scopes it receives.
|
||||
*
|
||||
* @see {@link com.github.jreddit.oauth.RedditToken}
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class RedditTokenCompleteScope {
|
||||
|
||||
/** Set of scopes. */
|
||||
private Set<String> scopes;
|
||||
|
||||
/**
|
||||
* @param scopes List of scopes (e.g. "flair,edit")
|
||||
*/
|
||||
public RedditTokenCompleteScope(String scopes) {
|
||||
|
||||
// Create set
|
||||
this.scopes = new HashSet<String>();
|
||||
|
||||
// Split up
|
||||
String[] split = scopes.split(RedditScope.SEPARATOR);
|
||||
|
||||
// Add each to the set
|
||||
for (String s : split) {
|
||||
this.scopes.add(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether it has this scope.
|
||||
*
|
||||
* @param scope Reddit scope
|
||||
*
|
||||
* @return Does it have this scope?
|
||||
*/
|
||||
public boolean has(RedditScope scope) {
|
||||
return scopes.contains(scope.value());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToBoolean;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToDouble;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToInteger;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.github.jreddit.parser.entity.imaginary.CommentTreeElement;
|
||||
import com.github.jreddit.parser.entity.imaginary.MixedListingElement;
|
||||
|
||||
/**
|
||||
* A Reddit comment. Contains the edited timestamp, the body
|
||||
*
|
||||
* @author Benjamin Jakobus
|
||||
* @author Raul Rene Lepsa
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class Comment extends Thing implements CommentTreeElement, MixedListingElement {
|
||||
|
||||
private String author; // Username of the author
|
||||
private String parentId; // Parent identifier
|
||||
private String subreddit; // Subreddit name
|
||||
private String subredditId; // Subreddit identifier
|
||||
private String linkId; // Submission (aka. link) identifier
|
||||
private String bodyHTML; // The body with HTML markup
|
||||
private Boolean scoreHidden; // Whether the score is hidden
|
||||
private String body; // The actual body
|
||||
private Boolean edited; // Edited timestamp
|
||||
private double created; // Created timestamp
|
||||
private double createdUTC; // Created UTC timestamp
|
||||
private List<CommentTreeElement> replies; // Replies if retrieved
|
||||
private Integer gilded; // Amount of times the comment been gilded
|
||||
private Integer score; // Karma score
|
||||
private Integer upvotes; // Number of upvotes that this body received
|
||||
private Integer downvotes; // Number of downvotes that this body received
|
||||
|
||||
// Possible fields to add as well:
|
||||
// private String bannedBy;
|
||||
// String likes;
|
||||
// private String approvedBy;
|
||||
// private String authorFlairCSSClass;
|
||||
// private String authorFlairText;
|
||||
// String num_reports = null;
|
||||
// String distinguished = null;
|
||||
|
||||
public Comment(JSONObject obj) {
|
||||
super(safeJsonToString(obj.get("name")));
|
||||
|
||||
this.setAuthor(safeJsonToString(obj.get("author")));
|
||||
this.setParentId(safeJsonToString(obj.get("parent_id")));
|
||||
this.setBody(safeJsonToString(obj.get("body")));
|
||||
this.setEdited(safeJsonToBoolean(obj.get("edited")));
|
||||
this.setCreated(safeJsonToDouble(obj.get("created")));
|
||||
this.setCreatedUTC(safeJsonToDouble(obj.get("created_utc")));
|
||||
this.setGilded(safeJsonToInteger(obj.get("gilded")));
|
||||
this.setScore(safeJsonToInteger(obj.get("score")));
|
||||
this.setUpvotes(safeJsonToInteger(obj.get("ups")));
|
||||
this.setDownvotes(safeJsonToInteger(obj.get("downs")));
|
||||
this.setSubreddit(safeJsonToString(obj.get("subreddit")));
|
||||
this.setSubredditId(safeJsonToString(obj.get("subreddit_id")));
|
||||
this.setLinkId(safeJsonToString(obj.get("link_id")));
|
||||
this.setBodyHTML(safeJsonToString(obj.get("body_html")));
|
||||
this.setScoreHidden(safeJsonToBoolean(obj.get("score_hidden")));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the replies of this comment.
|
||||
*
|
||||
* @return Replies (will <i>always</i> initialized, and empty if there are no replies)
|
||||
*/
|
||||
public List<CommentTreeElement> getReplies() {
|
||||
return this.replies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the replies of this comment.
|
||||
*
|
||||
* @param replies Comment tree of replies
|
||||
*/
|
||||
public void setReplies(List<CommentTreeElement> replies) {
|
||||
this.replies = replies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the username of the author.
|
||||
*
|
||||
* @return Username of the author
|
||||
*/
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username of the author
|
||||
*
|
||||
* @param author Username of the author
|
||||
*/
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public Boolean getEdited() {
|
||||
return edited;
|
||||
}
|
||||
|
||||
public void setEdited(Boolean edited) {
|
||||
this.edited = edited;
|
||||
}
|
||||
|
||||
public double getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(double created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public Integer getGilded() {
|
||||
return gilded;
|
||||
}
|
||||
|
||||
public void setGilded(Integer gilded) {
|
||||
this.gilded = gilded;
|
||||
}
|
||||
|
||||
public Integer getUpvotes() {
|
||||
return upvotes;
|
||||
}
|
||||
|
||||
public void setUpvotes(Integer upvotes) {
|
||||
this.upvotes = upvotes;
|
||||
}
|
||||
|
||||
public Integer getDownvotes() {
|
||||
return downvotes;
|
||||
}
|
||||
|
||||
public void setDownvotes(Integer downvotes) {
|
||||
this.downvotes = downvotes;
|
||||
}
|
||||
|
||||
public double getCreatedUTC() {
|
||||
return createdUTC;
|
||||
}
|
||||
|
||||
public void setCreatedUTC(double createdUTC) {
|
||||
this.createdUTC = createdUTC;
|
||||
}
|
||||
|
||||
public Integer getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public void setScore(Integer score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the subreddit
|
||||
*/
|
||||
public String getSubreddit() {
|
||||
return subreddit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param subreddit the subreddit to set
|
||||
*/
|
||||
public void setSubreddit(String subreddit) {
|
||||
this.subreddit = subreddit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the subredditId
|
||||
*/
|
||||
public String getSubredditId() {
|
||||
return subredditId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param subredditId the subredditId to set
|
||||
*/
|
||||
public void setSubredditId(String subredditId) {
|
||||
this.subredditId = subredditId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the linkId
|
||||
*/
|
||||
public String getLinkId() {
|
||||
return linkId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param linkId the linkId to set
|
||||
*/
|
||||
public void setLinkId(String linkId) {
|
||||
this.linkId = linkId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bodyHTML
|
||||
*/
|
||||
public String getBodyHTML() {
|
||||
return bodyHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bodyHTML the bodyHTML to set
|
||||
*/
|
||||
public void setBodyHTML(String bodyHTML) {
|
||||
this.bodyHTML = bodyHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scoreHidden
|
||||
*/
|
||||
public Boolean isScoreHidden() {
|
||||
return scoreHidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scoreHidden the scoreHidden to set
|
||||
*/
|
||||
public void setScoreHidden(Boolean scoreHidden) {
|
||||
this.scoreHidden = scoreHidden;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Comment(" + identifier + ")<" + ((body.length() > 10) ? body.substring(0, 10) : body) + ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof Comment && this.getFullName().equals(((Comment) other).getFullName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.hashCode() * this.getFullName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Thing o) {
|
||||
return this.getFullName().compareTo(o.getFullName());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
/**
|
||||
* Enumeration to represent the different types of Things.
|
||||
*/
|
||||
public enum Kind {
|
||||
|
||||
COMMENT("t1"), ACCOUNT("t2"), LINK("t3"), MESSAGE("t4"), SUBREDDIT("t5"), AWARD("t6"), PROMO_CAMPAIGN("t8"), MORE("more"), LISTING("listing");
|
||||
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Type enumeration constructor.
|
||||
* @param value String representation
|
||||
*/
|
||||
Kind(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of the type.
|
||||
* @return Type String representation.
|
||||
*/
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a string with its respective kind.
|
||||
*
|
||||
* @param t String kind (e.g. "t1" or "t5")
|
||||
*
|
||||
* @return Match kind (null, it not found)
|
||||
*/
|
||||
public static Kind match(String t) {
|
||||
for (Kind k : Kind.values()) {
|
||||
if (k.value().equals(t)) {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Encapsulates the private messages.
|
||||
* Corresponds to the <code>Kind.MESSAGES</code>, which is has the value t4 for the Reddit API
|
||||
*
|
||||
* @author Karan Goel
|
||||
* @author Raul Rene Lepsa
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class Message {
|
||||
|
||||
// The ID of this message
|
||||
private String id;
|
||||
|
||||
// Name - a combination of the Message Type (t4) and the ID of the message
|
||||
private String fullName;
|
||||
|
||||
// Name of the author of the message
|
||||
private String author;
|
||||
|
||||
// Recipient of the message
|
||||
private String recipient;
|
||||
|
||||
// The body of the message
|
||||
private String body;
|
||||
|
||||
// HTML version of the Body
|
||||
private String bodyHtml;
|
||||
|
||||
// If the message was a comment or not
|
||||
private boolean isComment;
|
||||
|
||||
// If it is a comment, it has a parent
|
||||
private String parentId;
|
||||
|
||||
// Timestamp of when the message was created
|
||||
private String created;
|
||||
|
||||
// UTC timestamp of when the message was created
|
||||
private String createdUTC;
|
||||
|
||||
// The content of the message
|
||||
private String context;
|
||||
|
||||
// The subject of the message
|
||||
private String subject;
|
||||
|
||||
public Message(JSONObject jsonObject) {
|
||||
|
||||
this.setBody(jsonObject.get("body").toString());
|
||||
this.setComment(Boolean.valueOf(jsonObject.get("was_comment").toString()));
|
||||
this.setFullName(jsonObject.get("name").toString());
|
||||
if (jsonObject.get("author") == null)
|
||||
{
|
||||
this.setAuthor("reddit");
|
||||
} else {
|
||||
this.setAuthor(jsonObject.get("author").toString());
|
||||
}
|
||||
this.setCreated(jsonObject.get("created").toString());
|
||||
this.setRecipient(jsonObject.get("dest").toString());
|
||||
this.setCreatedUTC(jsonObject.get("created_utc").toString());
|
||||
this.setBodyHtml(jsonObject.get("body_html").toString());
|
||||
this.setSubject(jsonObject.get("subject").toString());
|
||||
this.setContext(jsonObject.get("context").toString());
|
||||
this.setId(jsonObject.get("id").toString());
|
||||
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public void setRecipient(String recipient) {
|
||||
this.recipient = recipient;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getBodyHtml() {
|
||||
return bodyHtml;
|
||||
}
|
||||
|
||||
public void setBodyHtml(String bodyHtml) {
|
||||
this.bodyHtml = bodyHtml;
|
||||
}
|
||||
|
||||
public boolean isComment() {
|
||||
return isComment;
|
||||
}
|
||||
|
||||
public void setComment(boolean isComment) {
|
||||
this.isComment = isComment;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
public void setFullName(String fullName) {
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
public String getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(String created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public String getCreatedUTC() {
|
||||
return createdUTC;
|
||||
}
|
||||
|
||||
public void setCreatedUTC(String createdUTC) {
|
||||
this.createdUTC = createdUTC;
|
||||
}
|
||||
|
||||
public String getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void setContext(String context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public void setSubject(String subject) {
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
/**
|
||||
* Deal with different types of messages
|
||||
*
|
||||
* @author Raul Rene Lepsa
|
||||
*/
|
||||
public enum MessageType {
|
||||
|
||||
INBOX("inbox"), SENT("sent"), UNREAD("unread");
|
||||
|
||||
private String value;
|
||||
|
||||
MessageType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.github.jreddit.parser.entity.imaginary.CommentTreeElement;
|
||||
import com.github.jreddit.parser.util.JsonUtils;
|
||||
|
||||
/**
|
||||
* MORE entity. Can only exist in a comment tree, and thus
|
||||
* implements the <i>CommenTreeElement</i> interface.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class More extends Thing implements CommentTreeElement {
|
||||
|
||||
/** List of comment identifiers (ID36) that are his children. */
|
||||
private List<String> children;
|
||||
|
||||
/** Counting number assigned by reddit (does not tell much in a comment tree). */
|
||||
private Long count;
|
||||
|
||||
/** Parent comment fullname. */
|
||||
private String parentId;
|
||||
|
||||
/**
|
||||
* Construct a "More" thing.
|
||||
*
|
||||
* @param obj JSON object
|
||||
*/
|
||||
public More(JSONObject obj) {
|
||||
super(Kind.MORE.value() + "_NONE");
|
||||
|
||||
// The obj.get("name") and obj.get("id") are neglected, as these
|
||||
// are already implicitly included in the children array.
|
||||
|
||||
// Retrieve count from JSON
|
||||
this.count = JsonUtils.safeJsonToLong(obj.get("count"));
|
||||
|
||||
// Retrieve parent identifier from JSON
|
||||
this.parentId = JsonUtils.safeJsonToString(obj.get("parent_id"));
|
||||
|
||||
// Iterate over children
|
||||
this.children = new ArrayList<String>();
|
||||
JSONArray jsonChildren = (JSONArray) obj.get("children");
|
||||
for (Object child : jsonChildren) {
|
||||
this.children.add(JsonUtils.safeJsonToString(child));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the children ID36 comment identifiers.
|
||||
*
|
||||
* @return The children (e.g. ["dja241", "dsfjak24"])
|
||||
*/
|
||||
public List<String> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the counting number assigned by reddit (does not tell much in this case).
|
||||
*
|
||||
* @return The counting number
|
||||
*/
|
||||
public Long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve how many children (comments) the MORE hides.
|
||||
*
|
||||
* @return How many comments the more hides ({@link #getChildren()}'s size)
|
||||
*/
|
||||
public int getChildrenSize() {
|
||||
return children.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the parent fullname comment identifier.
|
||||
*
|
||||
* @return The parent identifier (e.g. "t1_38942f")
|
||||
*/
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Thing o) {
|
||||
if (!(o instanceof More)) {
|
||||
return 1;
|
||||
} else {
|
||||
return ((More) o).getChildren().equals(this.getChildren()) ? 0 : -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "More()<" + this.getChildrenSize() + " more directly underneath>";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,546 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToBoolean;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToDouble;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToLong;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToString;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.github.jreddit.parser.entity.imaginary.MixedListingElement;
|
||||
|
||||
|
||||
/**
|
||||
* This class represents a vote on a link submission on Reddit.
|
||||
*
|
||||
* @author Omer Elnour
|
||||
* @author Andrei Sfat
|
||||
* @author Raul Rene Lepsa
|
||||
* @author Jonny Krysh
|
||||
* @author Danny Tsegai
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class Submission extends Thing implements MixedListingElement {
|
||||
|
||||
/* All String values */
|
||||
private String url;
|
||||
private String permalink;
|
||||
private String author;
|
||||
private String title;
|
||||
private String subreddit;
|
||||
private String subredditId;
|
||||
private String thumbnail;
|
||||
private String selftext;
|
||||
private String selftextHTML;
|
||||
private String domain;
|
||||
private String bannedBy;
|
||||
private String approvedBy;
|
||||
private String authorFlairCSSClass;
|
||||
private String linkFlairCSSClass;
|
||||
private String authorFlairText;
|
||||
private String linkFlairText;
|
||||
private String distinguished;
|
||||
private String from;
|
||||
private String fromId;
|
||||
private String removalReason;
|
||||
private String fromKind;
|
||||
|
||||
/* All Long values */
|
||||
private Long gilded;
|
||||
private Long commentCount;
|
||||
private Long reportCount;
|
||||
private Long score;
|
||||
private Long upVotes;
|
||||
private Long downVotes;
|
||||
|
||||
/* All Double values */
|
||||
private Double created;
|
||||
private Double createdUTC;
|
||||
private Double upvoteRatio;
|
||||
|
||||
/* All Boolean values */
|
||||
private Boolean visited;
|
||||
private Boolean self;
|
||||
private Boolean saved;
|
||||
private Boolean edited;
|
||||
private Boolean stickied;
|
||||
private Boolean nsfw;
|
||||
private Boolean hidden;
|
||||
private Boolean clicked;
|
||||
private Boolean likes;
|
||||
|
||||
/**
|
||||
* Create a Submission from a JSONObject
|
||||
*
|
||||
* @param obj The JSONObject to load Submission data from
|
||||
*/
|
||||
public Submission(JSONObject obj) {
|
||||
super(safeJsonToString(obj.get("name")));
|
||||
|
||||
setURL(safeJsonToString(obj.get("url")));
|
||||
setPermalink(safeJsonToString(obj.get("permalink")));
|
||||
setAuthor(safeJsonToString(obj.get("author")));
|
||||
setTitle(safeJsonToString(obj.get("title")));
|
||||
setSubreddit(safeJsonToString(obj.get("subreddit")));
|
||||
setSubredditId(safeJsonToString(obj.get("subreddit_id")));
|
||||
setThumbnail(safeJsonToString(obj.get("thumbnail")));
|
||||
setSelftext(safeJsonToString(obj.get("selftext")));
|
||||
setSelftextHTML(safeJsonToString(obj.get("selftext_html")));
|
||||
setDomain(safeJsonToString(obj.get("domain")));
|
||||
setBannedBy(safeJsonToString(obj.get("banned_by")));
|
||||
setApprovedBy(safeJsonToString(obj.get("approved_by")));
|
||||
setAuthorFlairCSSClass(safeJsonToString(obj.get("author_flair_css_class")));
|
||||
setLinkFlairCSSClass(safeJsonToString(obj.get("link_flair_css_class")));
|
||||
setDistinguished(safeJsonToString(obj.get("distinguished")));
|
||||
setAuthorFlairText(safeJsonToString(obj.get("author_flair_text")));
|
||||
setLinkFlairText(safeJsonToString(obj.get("link_flair_text")));
|
||||
setFrom(safeJsonToString(obj.get("from")));
|
||||
setFromId(safeJsonToString(obj.get("from_id")));
|
||||
setRemovalReason(safeJsonToString(obj.get("removal_reason")));
|
||||
setFromKind(safeJsonToString(obj.get("from_kind")));
|
||||
|
||||
setGilded(safeJsonToLong(obj.get("gilded")));
|
||||
setCommentCount(safeJsonToLong(obj.get("num_comments")));
|
||||
setReportCount(safeJsonToLong(obj.get("num_reports")));
|
||||
setScore(safeJsonToLong(obj.get("score")));
|
||||
setUpVotes(safeJsonToLong(obj.get("ups")));
|
||||
setDownVotes(safeJsonToLong(obj.get("downs")));
|
||||
|
||||
setCreated(safeJsonToDouble(obj.get("created")));
|
||||
setCreatedUTC(safeJsonToDouble(obj.get("created_utc")));
|
||||
setUpvoteRatio(safeJsonToDouble(obj.get("upvote_ratio")));
|
||||
|
||||
setVisited(safeJsonToBoolean(obj.get("visited")));
|
||||
setSelf(safeJsonToBoolean(obj.get("is_self")));
|
||||
setSaved(safeJsonToBoolean(obj.get("saved")));
|
||||
setEdited(safeJsonToBoolean(obj.get("edited")));
|
||||
setStickied(safeJsonToBoolean(obj.get("stickied")));
|
||||
setNSFW(safeJsonToBoolean(obj.get("over_18")));
|
||||
setHidden(safeJsonToBoolean(obj.get("hidden")));
|
||||
setClicked(safeJsonToBoolean(obj.get("clicked")));
|
||||
setLikes(safeJsonToBoolean(obj.get("likes")));
|
||||
|
||||
}
|
||||
|
||||
public String getFromKind() {
|
||||
return fromKind;
|
||||
}
|
||||
|
||||
private void setFromKind(String fromKind) {
|
||||
this.fromKind = fromKind;
|
||||
}
|
||||
|
||||
public String getRemovalReason() {
|
||||
return removalReason;
|
||||
}
|
||||
|
||||
private void setRemovalReason(String removalReason) {
|
||||
this.removalReason = removalReason;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
private void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public String getFromId() {
|
||||
return fromId;
|
||||
}
|
||||
|
||||
private void setFromId(String fromId) {
|
||||
this.fromId = fromId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Up-vote ratio (total number of up-votes divided by total number of votes)
|
||||
*/
|
||||
public Double getUpvoteRatio() {
|
||||
return upvoteRatio;
|
||||
}
|
||||
|
||||
private void setUpvoteRatio(Double upvoteRatio) {
|
||||
this.upvoteRatio = upvoteRatio;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The CSS class of the author
|
||||
*/
|
||||
public String getAuthorFlairCSSClass() {
|
||||
return authorFlairCSSClass;
|
||||
}
|
||||
|
||||
private void setAuthorFlairCSSClass(String authorFlairCSSClass) {
|
||||
this.authorFlairCSSClass = authorFlairCSSClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The text of the flair of the author
|
||||
*/
|
||||
public String getAuthorFlairText() {
|
||||
return authorFlairText;
|
||||
}
|
||||
|
||||
private void setAuthorFlairText(String authorFlairText) {
|
||||
this.authorFlairText = authorFlairText;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Flair text of the submission ('link')
|
||||
*/
|
||||
public String getLinkFlairText() {
|
||||
return linkFlairText;
|
||||
}
|
||||
|
||||
private void setLinkFlairText(String linkFlairText) {
|
||||
this.linkFlairText = linkFlairText;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The CSS class of the submission ('link') flair
|
||||
*/
|
||||
public String getLinkFlairCSSClass() {
|
||||
return linkFlairCSSClass;
|
||||
}
|
||||
|
||||
private void setLinkFlairCSSClass(String linkFlairCSSClass) {
|
||||
this.linkFlairCSSClass = linkFlairCSSClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the post is distinguished (e.g. by a "moderator")
|
||||
*/
|
||||
public String getDistinguished() {
|
||||
return distinguished;
|
||||
}
|
||||
|
||||
private void setDistinguished(String distinguished) {
|
||||
this.distinguished = distinguished;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the user that authenticated the retrieval of this submission upvoted it
|
||||
*/
|
||||
public Boolean getLikes() {
|
||||
return likes;
|
||||
}
|
||||
|
||||
private void setLikes(Boolean likes) {
|
||||
this.likes = likes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The username of the one that approved this submission to the subreddit it belongs to
|
||||
*/
|
||||
public String getApprovedBy() {
|
||||
return approvedBy;
|
||||
}
|
||||
|
||||
private void setApprovedBy(String approvedBy) {
|
||||
this.approvedBy = approvedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the user that authenticated the retrieval of this submission has hidden it
|
||||
*/
|
||||
public Boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
|
||||
private void setHidden(Boolean hidden) {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the user that authenticated the retrieval of this submission has already clicked on it before
|
||||
*/
|
||||
public Boolean isClicked() {
|
||||
return clicked;
|
||||
}
|
||||
|
||||
private void setClicked(Boolean clicked) {
|
||||
this.clicked = clicked;
|
||||
}
|
||||
|
||||
public void setUpVotes(Long upVotes) {
|
||||
this.upVotes = upVotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The score (number of upvotes minus number of downvotes)
|
||||
*/
|
||||
public Long getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
private void setScore(Long score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public void setCreatedUTC(Double createdUTC) {
|
||||
this.createdUTC = createdUTC;
|
||||
}
|
||||
|
||||
public void setDownVotes(Long downVotes) {
|
||||
this.downVotes = downVotes;
|
||||
}
|
||||
|
||||
public void setCommentCount(Long commentCount) {
|
||||
this.commentCount = commentCount;
|
||||
}
|
||||
|
||||
public void setSubreddit(String subreddit) {
|
||||
this.subreddit = subreddit;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setURL(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getPermalink() {
|
||||
return permalink;
|
||||
}
|
||||
|
||||
public void setPermalink(String permalink) {
|
||||
this.permalink = permalink;
|
||||
}
|
||||
|
||||
public Long getCommentCount() {
|
||||
return commentCount;
|
||||
}
|
||||
|
||||
public Long getUpVotes() {
|
||||
return upVotes;
|
||||
}
|
||||
|
||||
public Long getDownVotes() {
|
||||
return downVotes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Double getCreatedUTC() {
|
||||
return createdUTC;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Title of the submission
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Subreddit name (e.g. "programming')
|
||||
*/
|
||||
public String getSubreddit() {
|
||||
return subreddit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Subreddit ID36 identifier
|
||||
*/
|
||||
public String getSubredditId() {
|
||||
return subredditId;
|
||||
}
|
||||
|
||||
public void setSubredditId(String subredditId) {
|
||||
this.subredditId = subredditId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Thumbnail image URL
|
||||
*/
|
||||
public String getThumbnail() {
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
private void setThumbnail(String thumbnail) {
|
||||
this.thumbnail = thumbnail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The self text of the submission (written by the author)
|
||||
*/
|
||||
public String getSelftext() {
|
||||
return selftext;
|
||||
}
|
||||
|
||||
private void setSelftext(String selftext) {
|
||||
this.selftext = selftext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The self text of the submission in HTML (written by the author)
|
||||
*/
|
||||
public String getSelftextHTML() {
|
||||
return selftextHTML;
|
||||
}
|
||||
|
||||
private void setSelftextHTML(String selftextHTML) {
|
||||
this.selftextHTML = selftextHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The domain of the URL this submission links to
|
||||
*/
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
private void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The username of the moderator that banned this submission
|
||||
*/
|
||||
public String getBannedBy() {
|
||||
return bannedBy;
|
||||
}
|
||||
|
||||
private void setBannedBy(String bannedBy) {
|
||||
this.bannedBy = bannedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Count of how many times this submission received gold ('was gilded')
|
||||
*/
|
||||
public Long getGilded() {
|
||||
return gilded;
|
||||
}
|
||||
|
||||
private void setGilded(Long gilded) {
|
||||
this.gilded = gilded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Count of how many times this submission was reported
|
||||
*/
|
||||
public Long getReportCount() {
|
||||
return reportCount;
|
||||
}
|
||||
|
||||
private void setReportCount(Long reportCount) {
|
||||
this.reportCount = reportCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The created time-stamp (ms since Unix epoch)
|
||||
*/
|
||||
public Double getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
private void setCreated(Double created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the user that authenticated the retrieval of this submission has already visited it before
|
||||
*/
|
||||
public Boolean isVisited() {
|
||||
return visited;
|
||||
}
|
||||
|
||||
private void setVisited(Boolean visited) {
|
||||
this.visited = visited;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether it is a self post
|
||||
*/
|
||||
public Boolean isSelf() {
|
||||
return self;
|
||||
}
|
||||
|
||||
private void setSelf(Boolean self) {
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the user that authenticated the retrieval of this submission has saved it
|
||||
*/
|
||||
public Boolean isSaved() {
|
||||
return saved;
|
||||
}
|
||||
|
||||
private void setSaved(Boolean saved) {
|
||||
this.saved = saved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the submission has been edited
|
||||
*/
|
||||
public Boolean isEdited() {
|
||||
return edited;
|
||||
}
|
||||
|
||||
private void setEdited(Boolean edited) {
|
||||
this.edited = edited;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the submission is sticked to the top of the subreddit
|
||||
*/
|
||||
public Boolean isStickied() {
|
||||
return stickied;
|
||||
}
|
||||
|
||||
private void setStickied(Boolean stickied) {
|
||||
this.stickied = stickied;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the post is Not Suited For Work (contains adult content)
|
||||
*/
|
||||
public Boolean isNSFW() {
|
||||
return nsfw;
|
||||
}
|
||||
|
||||
private void setNSFW(Boolean nsfw) {
|
||||
this.nsfw = nsfw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Submission(" + this.getFullName() + ")<" + title + ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof Submission && this.getFullName().equals(((Submission) other).getFullName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.hashCode() * this.getFullName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Thing o) {
|
||||
return this.getFullName().compareTo(o.getFullName());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToBoolean;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToDouble;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToLong;
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToString;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Encapsulates a subreddit.
|
||||
*
|
||||
* @author Benjamin Jakobus
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public class Subreddit extends Thing {
|
||||
|
||||
private String displayName;
|
||||
private String title;
|
||||
private String url;
|
||||
private String description;
|
||||
private String subredditType;
|
||||
|
||||
private double created;
|
||||
private double createdUTC;
|
||||
|
||||
private Boolean nsfw;
|
||||
|
||||
private Long subscribers;
|
||||
|
||||
// Other possible fields
|
||||
|
||||
// Submit text HTML
|
||||
// String submit_text_html = null;
|
||||
|
||||
// Whether user is banned
|
||||
// Boolean user_is_banned = null;
|
||||
|
||||
// Submit text
|
||||
// String submit_text = "submit text for subreddit";
|
||||
|
||||
// Header image
|
||||
// String header_img = "http://a.thumbs.redditmedia.com/yyL5sveWcgkCPKbr.png";
|
||||
|
||||
// Description in HTML markup
|
||||
// String description_html = "<div>HTML description for subreddit</d>";
|
||||
|
||||
// Whether user is moderator
|
||||
// Boolean user_is_moderator = null;
|
||||
|
||||
// Header title
|
||||
// String header_title = "Header title for subreddit";
|
||||
|
||||
// Submit link title
|
||||
// String submit_link_label = "Submit link label";
|
||||
|
||||
// Accounts active
|
||||
// String accounts_active = null;
|
||||
|
||||
// Whether it allows public traffic
|
||||
// Boolean public_traffic = true;
|
||||
|
||||
// Size of header
|
||||
// JSONArray header_size = JsonHelpers.jsonArrayOf(160, 64);
|
||||
|
||||
// Submit text label
|
||||
// String submit_text_label = "Submit text label";
|
||||
|
||||
// Whether user is contributor
|
||||
// Boolean user_is_contributor = null;
|
||||
|
||||
// Public description
|
||||
// String public_description = "Public description of subreddit";
|
||||
|
||||
// Amount of minutes the comment score is hidden
|
||||
// long comment_score_hide_mins = 0;
|
||||
|
||||
// What types of submissions are allowed
|
||||
// String submission_type = "any";
|
||||
|
||||
// Whether the user is contributor
|
||||
// Boolean user_is_subscriber = null;
|
||||
|
||||
/**
|
||||
* Create a Submission from a JSONObject
|
||||
*
|
||||
* @param obj The JSONObject to load Submission data from
|
||||
*/
|
||||
public Subreddit(JSONObject obj) {
|
||||
super(safeJsonToString(obj.get("name")));
|
||||
|
||||
setDisplayName(safeJsonToString(obj.get("display_name")));
|
||||
setTitle(safeJsonToString(obj.get("title")));
|
||||
setURL(safeJsonToString(obj.get("url")));
|
||||
setCreated(safeJsonToDouble(obj.get("created")));
|
||||
setCreatedUTC(safeJsonToDouble(obj.get("created_utc")));
|
||||
setNSFW(safeJsonToBoolean(obj.get("over18")));
|
||||
setSubscribers(safeJsonToLong(obj.get("subscribers")));
|
||||
setDescription(safeJsonToString(obj.get("description")));
|
||||
setSubredditType(safeJsonToString(obj.get("subreddit_type")));
|
||||
|
||||
}
|
||||
|
||||
private void setCreated(double created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
private void setCreatedUTC(double createdUTC) {
|
||||
this.createdUTC = createdUTC;
|
||||
}
|
||||
|
||||
private void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
private void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
private void setNSFW(Boolean nsfw) {
|
||||
this.nsfw = nsfw;
|
||||
}
|
||||
|
||||
private void setSubscribers(long subscribers) {
|
||||
this.subscribers = subscribers;
|
||||
}
|
||||
|
||||
private void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
private void setURL(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Timestamp of when the subreddit was created.
|
||||
*/
|
||||
public double getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UTC timestamp of when the subreddit was created.
|
||||
*/
|
||||
public double getCreatedUTC() {
|
||||
return createdUTC;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Description detailing the subreddit.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The subreddit's display name.
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of subscribers for this subreddit.
|
||||
*/
|
||||
public long getSubscribers() {
|
||||
return subscribers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The subreddit's title.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The subreddit's URL.
|
||||
*/
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the subreddit is marked as containing adult content; false if not.
|
||||
*/
|
||||
public Boolean isNSFW() {
|
||||
return nsfw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of subreddit (e.g. "private" or "public")
|
||||
*/
|
||||
public String getSubredditType() {
|
||||
return subredditType;
|
||||
}
|
||||
|
||||
public void setSubredditType(String type) {
|
||||
this.subredditType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Subreddit(" + this.getFullName() + ")<" + this.getDisplayName() + ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (other instanceof Subreddit && this.getFullName().equals(((Subreddit) other).getFullName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.hashCode() * this.getFullName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Thing o) {
|
||||
return this.getFullName().compareTo(o.getFullName());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
/**
|
||||
* This class represents a reddit "thing"
|
||||
*
|
||||
* @author <a href="http://www.omrlnr.com">Omer Elnour</a>
|
||||
* @author Simon Kassing
|
||||
* @see <a href="http://www.reddit.com/dev/api#fullname">Reddit API Reference</a>
|
||||
*/
|
||||
public abstract class Thing implements Comparable<Thing> {
|
||||
|
||||
/**
|
||||
* The kind of this thing.
|
||||
*
|
||||
* @see <a href="http://www.reddit.com/dev/api#fullnames">Reddit API Reference for full names (section 'kind prefixes')</a>
|
||||
*/
|
||||
protected final Kind kind;
|
||||
|
||||
/**
|
||||
* The identifier of this thing.
|
||||
*
|
||||
* @see <a href="http://www.reddit.com/dev/api#fullnames">Reddit API Reference for full names (section 'identifier')</a>
|
||||
*/
|
||||
protected final String identifier;
|
||||
|
||||
/**
|
||||
* The full name of this thing.
|
||||
* Combination of its kind ({@link #getKind() getKind}) and its unique ID.
|
||||
*
|
||||
* @see <a href="http://www.reddit.com/dev/api#fullnames">Reddit API Reference for full names</a>
|
||||
*/
|
||||
protected final String fullName;
|
||||
|
||||
/**
|
||||
* Constructor. Must be called.
|
||||
* @param name Full name of the thing
|
||||
*/
|
||||
public Thing(String name) {
|
||||
assert name.contains("_") : "A full name must contain an underscore.";
|
||||
this.fullName = name;
|
||||
String[] split = name.split("_");
|
||||
this.kind = Kind.match(split[0]);
|
||||
this.identifier = split[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the kind of this thing.
|
||||
* Example: t3 indicates a kind 3 (a link).
|
||||
*
|
||||
* @see <a href="http://www.reddit.com/dev/api#fullnames">Reddit API Reference for full names (section 'kind prefixes')</a>
|
||||
*/
|
||||
public Kind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the identifier of this thing.
|
||||
* Example: 15bfi0.
|
||||
*
|
||||
* @see <a href="http://www.reddit.com/dev/api#fullnames">Reddit API Reference for full names (section 'identifier')</a>
|
||||
*/
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the full name of this thing.
|
||||
* Combination of its kind (see {@link #getKind() getKind}) and its unique ID, combined with a underscore.
|
||||
* Example: t3_15bfi0 indicates a kind 3 (a link) and as unique identifier 15bfi0.
|
||||
*
|
||||
* @see <a href="http://www.reddit.com/dev/api#fullnames">Reddit API Reference for full names</a>
|
||||
*/
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
package com.github.jreddit.parser.entity;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Encapsulates user information (regarding karma, emails, identifiers, statuses, created time and current modhash)
|
||||
*
|
||||
* @author Raul Rene Lepsa
|
||||
*/
|
||||
public class UserInfo {
|
||||
|
||||
// User identifier
|
||||
private String id;
|
||||
|
||||
// The user's name
|
||||
private String name;
|
||||
|
||||
// Modhash token
|
||||
private String modhash;
|
||||
|
||||
// Karma points for all the comments
|
||||
private long commentKarma;
|
||||
|
||||
// Karma points for all the submitted links
|
||||
private long linkKarma;
|
||||
|
||||
// Whether the user is a moderator
|
||||
private boolean isMod;
|
||||
|
||||
// Whether or not the user has moderator email
|
||||
private Boolean hasModMail;
|
||||
|
||||
// Whether the account is associated with an email address
|
||||
private Boolean hasMail;
|
||||
|
||||
// Indicates whether the user has verified the email address
|
||||
private Boolean hasVerifiedEmail;
|
||||
|
||||
// Whether the user is a gold member
|
||||
private boolean isGold;
|
||||
|
||||
// Timestamp of the creation date
|
||||
private double created;
|
||||
|
||||
// UTC timestamp of creation date
|
||||
private double createdUTC;
|
||||
|
||||
// Indicates whether this user is friends with the currently connected one. Believe it or not, you can actually be
|
||||
// friends with yourself. http://www.reddit.com/r/reddit.com/comments/duf7q/random_reddit_protip_you_can_add_yourself_as_a/
|
||||
private boolean isFriend;
|
||||
|
||||
// Indicates whether the user is over 18
|
||||
private Boolean over18;
|
||||
|
||||
public UserInfo() {
|
||||
|
||||
}
|
||||
|
||||
public UserInfo(JSONObject info) {
|
||||
|
||||
setHasMail((Boolean) info.get("has_mail"));
|
||||
setHasModMail((Boolean) info.get("has_mod_mail"));
|
||||
setCommentKarma((Long) info.get("comment_karma"));
|
||||
setCreatedUTC((Double) info.get("created_utc"));
|
||||
setGold((Boolean) info.get("is_gold"));
|
||||
setLinkKarma((Long) info.get("link_karma"));
|
||||
setMod((Boolean) info.get("is_mod"));
|
||||
setFriend((Boolean) info.get("is_friend"));
|
||||
setModhash((String) info.get("modhash"));
|
||||
setHasVerifiedEmail((Boolean) info.get("has_verified_email"));
|
||||
setId((String) info.get("id"));
|
||||
setOver18((Boolean) info.get("over_18"));
|
||||
setCreated((Double) info.get("created"));
|
||||
setName((String) info.get("name"));
|
||||
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getModhash() {
|
||||
return modhash;
|
||||
}
|
||||
|
||||
public void setModhash(String modhash) {
|
||||
this.modhash = modhash;
|
||||
}
|
||||
|
||||
public long getCommentKarma() {
|
||||
return commentKarma;
|
||||
}
|
||||
|
||||
public void setCommentKarma(long commentKarma) {
|
||||
this.commentKarma = commentKarma;
|
||||
}
|
||||
|
||||
public long getLinkKarma() {
|
||||
return linkKarma;
|
||||
}
|
||||
|
||||
public void setLinkKarma(long linkKarma) {
|
||||
this.linkKarma = linkKarma;
|
||||
}
|
||||
|
||||
public boolean isMod() {
|
||||
return isMod;
|
||||
}
|
||||
|
||||
public void setMod(boolean isMod) {
|
||||
this.isMod = isMod;
|
||||
}
|
||||
|
||||
public Boolean getHasModMail() {
|
||||
return hasModMail;
|
||||
}
|
||||
|
||||
public void setHasModMail(Boolean hasModMail) {
|
||||
this.hasModMail = hasModMail;
|
||||
}
|
||||
|
||||
public Boolean getHasMail() {
|
||||
return hasMail;
|
||||
}
|
||||
|
||||
public void setHasMail(Boolean hasMail) {
|
||||
this.hasMail = hasMail;
|
||||
}
|
||||
|
||||
public Boolean isHasVerifiedEmail() {
|
||||
return hasVerifiedEmail;
|
||||
}
|
||||
|
||||
public void setHasVerifiedEmail(Boolean hasVerifiedEmail) {
|
||||
this.hasVerifiedEmail = hasVerifiedEmail;
|
||||
}
|
||||
|
||||
public boolean isGold() {
|
||||
return isGold;
|
||||
}
|
||||
|
||||
public void setGold(boolean isGold) {
|
||||
this.isGold = isGold;
|
||||
}
|
||||
|
||||
public double getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(double created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public double getCreatedUTC() {
|
||||
return createdUTC;
|
||||
}
|
||||
|
||||
public void setCreatedUTC(double createdUTC) {
|
||||
this.createdUTC = createdUTC;
|
||||
}
|
||||
|
||||
public boolean isFriend() {
|
||||
return isFriend;
|
||||
}
|
||||
|
||||
public void setFriend(boolean isFriend) {
|
||||
this.isFriend = isFriend;
|
||||
}
|
||||
|
||||
public Boolean getOver18() {
|
||||
return over18;
|
||||
}
|
||||
|
||||
public void setOver18(Boolean over18) {
|
||||
this.over18 = over18;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String newLine = System.getProperty("line.separator");
|
||||
|
||||
result.append("id: ").append(id).append(newLine)
|
||||
.append("name: ").append(name).append(newLine)
|
||||
.append("modhash: ").append(modhash).append(newLine)
|
||||
.append("commentKarma: ").append(commentKarma).append(newLine)
|
||||
.append("linkKarma: ").append(linkKarma).append(newLine)
|
||||
.append("isModerator: ").append(isMod).append(newLine)
|
||||
.append("hasModMail: ").append(hasModMail).append(newLine)
|
||||
.append("hasMail: ").append(hasMail).append(newLine)
|
||||
.append("hasVerifiedEmail: ").append(hasVerifiedEmail).append(newLine)
|
||||
.append("isGold: ").append(isGold).append(newLine)
|
||||
.append("Created: ").append(created).append(newLine)
|
||||
.append("CreatedUTC: ").append(createdUTC).append(newLine)
|
||||
.append("isFriend: ").append(isFriend).append(newLine)
|
||||
.append("over18: ").append(over18);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.github.jreddit.parser.entity.imaginary;
|
||||
|
||||
/**
|
||||
* Interface to abstract over the two possible elements in a
|
||||
* comment tree, namely a {@link Comment} or a {@link More} thing. If an object
|
||||
* is of the type of this interface, it means that it <i>must</i>
|
||||
* be either an {@link Comment} or a {@link More} thing.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*
|
||||
* @see com.github.jreddit.parser.entity.Comment
|
||||
* @see com.github.jreddit.parser.entity.More
|
||||
*/
|
||||
public interface CommentTreeElement {
|
||||
// Empty because only an abstraction for either a Comment or a More thing
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.github.jreddit.parser.entity.imaginary;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.github.jreddit.parser.entity.Submission;
|
||||
|
||||
public class FullSubmission {
|
||||
|
||||
private Submission submission;
|
||||
private List<CommentTreeElement> commentTree;
|
||||
|
||||
public FullSubmission(Submission submission, List<CommentTreeElement> commentTree) {
|
||||
this.submission = submission;
|
||||
this.commentTree = commentTree;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the submission
|
||||
*/
|
||||
public Submission getSubmission() {
|
||||
return submission;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the commentTree
|
||||
*/
|
||||
public List<CommentTreeElement> getCommentTree() {
|
||||
return commentTree;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.github.jreddit.parser.entity.imaginary;
|
||||
|
||||
/**
|
||||
* Interface to abstract over the two possible elements in a
|
||||
* mixed listing, namely a {@link Comment} or a {@link Submission} thing.
|
||||
* If an object is of the type of this interface, it means that it <i>must</i>
|
||||
* be either of the respective {@link Comment} or {@link Submission} class.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*
|
||||
* @see com.github.jreddit.parser.entity.Comment
|
||||
* @see com.github.jreddit.parser.entity.Submission
|
||||
*/
|
||||
public interface MixedListingElement {
|
||||
// Empty because only an abstraction for either a Comment or a Submission thing
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.github.jreddit.parser.exception;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
public class RedditParseException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -1031803118041533936L;
|
||||
|
||||
public RedditParseException(String custom) {
|
||||
super("Could not parse response from reddit (" + custom + ")");
|
||||
}
|
||||
|
||||
public RedditParseException(String custom, Throwable t) {
|
||||
super("Could not parse response from reddit (" + custom + ")", t);
|
||||
}
|
||||
|
||||
public RedditParseException() {
|
||||
this("undefined (null) response");
|
||||
}
|
||||
|
||||
public RedditParseException(int errorCode) {
|
||||
this("contained HTTP error code: " + errorCode);
|
||||
}
|
||||
|
||||
public RedditParseException(ParseException pe) {
|
||||
this("invalid JSON format", pe);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.github.jreddit.parser.listing;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.parser.entity.Comment;
|
||||
import com.github.jreddit.parser.entity.Thing;
|
||||
import com.github.jreddit.parser.exception.RedditParseException;
|
||||
|
||||
public class CommentsListingParser extends RedditListingParser {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CommentsListingParser.class);
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a list of comments.
|
||||
* This parser expects the JSON to be of a listing of comments.<br>
|
||||
* <br>
|
||||
* <i>Note: this parsing can only be performed on listings of comments, not on
|
||||
* a comment tree of a submission.</i>
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @return Parsed list of comments
|
||||
*
|
||||
* @throws ParseException
|
||||
* @throws RedditRequestException
|
||||
*/
|
||||
public List<Comment> parse(String jsonText) throws RedditParseException {
|
||||
|
||||
// Parse to a list of things
|
||||
List<Thing> things = this.parseGeneric(jsonText);
|
||||
|
||||
// List of comment and submission mixed elements
|
||||
List<Comment> comments = new LinkedList<Comment>();
|
||||
|
||||
// Iterate over things
|
||||
for (Thing t : things) {
|
||||
|
||||
if (t instanceof Comment) {
|
||||
comments.add((Comment) t);
|
||||
} else {
|
||||
LOGGER.warn("Encountered an unexpected reddit thing (" + t.getKind().value() + "), skipping it.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return resulting comments list
|
||||
return comments;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package com.github.jreddit.parser.listing;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.parser.entity.Comment;
|
||||
import com.github.jreddit.parser.entity.More;
|
||||
import com.github.jreddit.parser.entity.Thing;
|
||||
import com.github.jreddit.parser.entity.imaginary.CommentTreeElement;
|
||||
import com.github.jreddit.parser.exception.RedditParseException;
|
||||
|
||||
public class CommentsMoreParser extends RedditListingParser {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CommentsMoreParser.class);
|
||||
|
||||
private static final JSONParser JSON_PARSER = new JSONParser();
|
||||
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a list of new additional comment tree elements.
|
||||
* This parser expects the JSON to be of a listing of comments and more's.<br>
|
||||
* <br>
|
||||
* <i>Note: this parsing can only be performed on listings of comments and more's, not on
|
||||
* a comment tree of a submission.</i>
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @return Parsed list of comments
|
||||
*
|
||||
* @throws ParseException
|
||||
* @throws RedditRequestException
|
||||
*/
|
||||
public List<CommentTreeElement> parse(String jsonText) throws RedditParseException {
|
||||
|
||||
try {
|
||||
|
||||
// Parse JSON response
|
||||
Object response = JSON_PARSER.parse(jsonText);
|
||||
|
||||
// Validate main
|
||||
this.validate(response);
|
||||
|
||||
// Move to the main object
|
||||
JSONObject main = (JSONObject) ((JSONObject) response).get("json");
|
||||
|
||||
// List of comment and more mixed elements
|
||||
List<CommentTreeElement> elements = new LinkedList<CommentTreeElement>();
|
||||
|
||||
// If the main has data (it can happen that it does not, when no comments identifiers were passed along)
|
||||
if (main.get("data") != null) {
|
||||
|
||||
// Parse to a list of things
|
||||
List<Thing> things = this.parseGeneric(main.toJSONString(), "things");
|
||||
|
||||
// Iterate over things
|
||||
for (Thing t : things) {
|
||||
|
||||
if (t instanceof Comment) {
|
||||
elements.add((Comment) t);
|
||||
} else if (t instanceof More) {
|
||||
elements.add((More) t);
|
||||
} else {
|
||||
LOGGER.warn("Encountered an unexpected reddit thing (" + t.getKind().value() + "), skipping it.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return resulting element list
|
||||
return elements;
|
||||
|
||||
} catch (ParseException pe) {
|
||||
throw new RedditParseException(pe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.github.jreddit.parser.listing;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.parser.entity.Comment;
|
||||
import com.github.jreddit.parser.entity.Submission;
|
||||
import com.github.jreddit.parser.entity.Thing;
|
||||
import com.github.jreddit.parser.entity.imaginary.MixedListingElement;
|
||||
import com.github.jreddit.parser.exception.RedditParseException;
|
||||
|
||||
/**
|
||||
* Parser for a listing that has both submissions and comments mixed together.
|
||||
*
|
||||
* @author Simon Kassing
|
||||
*
|
||||
* @see MixedListingElement
|
||||
*/
|
||||
public class MixedListingParser extends RedditListingParser {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MixedListingParser.class);
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a list of submissions and comments.
|
||||
* This parser expects the JSON to be of a listing of submissions and comments.
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @return Parsed list of submissions
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public List<MixedListingElement> parse(String jsonText) throws RedditParseException {
|
||||
|
||||
// Parse to a list of things
|
||||
List<Thing> things = this.parseGeneric(jsonText);
|
||||
|
||||
// List of comment and submission mixed elements
|
||||
List<MixedListingElement> mixedElements = new LinkedList<MixedListingElement>();
|
||||
|
||||
// Iterate over things
|
||||
for (Thing t : things) {
|
||||
|
||||
if (t instanceof Comment) {
|
||||
mixedElements.add((Comment) t);
|
||||
} else if (t instanceof Submission) {
|
||||
mixedElements.add((Submission) t);
|
||||
} else {
|
||||
LOGGER.warn("Encountered an unexpected reddit thing (" + t.getKind().value() + "), skipping it.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return result
|
||||
return mixedElements;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
package com.github.jreddit.parser.listing;
|
||||
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToString;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.parser.entity.Comment;
|
||||
import com.github.jreddit.parser.entity.Kind;
|
||||
import com.github.jreddit.parser.entity.More;
|
||||
import com.github.jreddit.parser.entity.Submission;
|
||||
import com.github.jreddit.parser.entity.Subreddit;
|
||||
import com.github.jreddit.parser.entity.Thing;
|
||||
import com.github.jreddit.parser.exception.RedditParseException;
|
||||
import com.github.jreddit.parser.util.JsonUtils;
|
||||
|
||||
public class RedditListingParser {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RedditListingParser.class);
|
||||
|
||||
protected static final JSONParser JSON_PARSER = new JSONParser();
|
||||
|
||||
/**
|
||||
* Validate that it is indeed the starting of a listing of reddit things.
|
||||
*
|
||||
* @param response Object returned by JSON parser
|
||||
*
|
||||
* @throws RedditRequestException If the response is not valid listing of reddit things
|
||||
*/
|
||||
public void validate(Object response) throws RedditParseException {
|
||||
|
||||
// Check for null
|
||||
if (response == null) {
|
||||
throw new RedditParseException();
|
||||
}
|
||||
|
||||
// Check it is a JSON response
|
||||
if (!(response instanceof JSONObject)) {
|
||||
throw new RedditParseException("not a JSON response");
|
||||
}
|
||||
|
||||
// Cast to JSON object
|
||||
JSONObject jsonResponse = ((JSONObject) response);
|
||||
|
||||
// Check for error
|
||||
if (jsonResponse.get("error") != null) {
|
||||
throw new RedditParseException(JsonUtils.safeJsonToInteger(jsonResponse.get("error")));
|
||||
}
|
||||
|
||||
// Check that data exists
|
||||
if (jsonResponse.get("data") == null && jsonResponse.get("json") == null) {
|
||||
throw new RedditParseException("data is missing from listing");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a list of things.
|
||||
* This parser expects the JSON to be of a listing of things, and supports
|
||||
* the following things: <i>More</i>, <i>Comment</i>, <i>Submission</i>, and <i>Subreddit</i>.
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @return Parsed list of things
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public List<Thing> parseGeneric(String jsonText) throws RedditParseException {
|
||||
return parseGeneric(jsonText, "children");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a list of things.
|
||||
* This parser expects the JSON to be of a listing of things, and supports
|
||||
* the following things: <i>More</i>, <i>Comment</i>, <i>Submission</i>, and <i>Subreddit</i>.<br>
|
||||
* <br>
|
||||
* <i>Note: if it encounters an invalid element (e.g. missing kind or data), it will
|
||||
* log a warning using SLF4J and would return null.</i>
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @param listingName Name of the listing name within the data
|
||||
*
|
||||
* @return Parsed list of things
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public List<Thing> parseGeneric(String jsonText, String listingName) throws RedditParseException {
|
||||
|
||||
try {
|
||||
|
||||
// List of submissions
|
||||
List<Thing> things = new LinkedList<Thing>();
|
||||
|
||||
// Send request to reddit server via REST client
|
||||
Object response = JSON_PARSER.parse(jsonText);
|
||||
|
||||
// Check for reddit error, can throw a RedditError
|
||||
validate(response);
|
||||
|
||||
// Cast to a JSON object
|
||||
JSONObject object = (JSONObject) response;
|
||||
|
||||
// Get the array of children
|
||||
JSONArray array = (JSONArray) ((JSONObject) object.get("data")).get(listingName);
|
||||
|
||||
// Iterate over array of children
|
||||
for (Object element : array) {
|
||||
|
||||
// Get the element
|
||||
JSONObject data = (JSONObject) element;
|
||||
|
||||
// Make sure it is of the correct kind
|
||||
String kindData = safeJsonToString(data.get("kind"));
|
||||
Object objData = data.get("data");
|
||||
|
||||
// If no kind is given
|
||||
if (kindData == null) {
|
||||
LOGGER.warn("Kind data missing, skipping it.");
|
||||
|
||||
// If no data is given
|
||||
} else if (objData == null || !(objData instanceof JSONObject)) {
|
||||
LOGGER.warn("Object data missing, skipping it.");
|
||||
|
||||
} else {
|
||||
|
||||
// Attempt to match
|
||||
Kind kind = Kind.match(kindData);
|
||||
|
||||
// Parse the thing
|
||||
Thing thing = parseThing(kind, ((JSONObject) data.get("data")));
|
||||
|
||||
// Show warning if failed
|
||||
if (thing == null) {
|
||||
LOGGER.warn("Encountered invalid kind for a listing (" + kindData + "), skipping it.");
|
||||
|
||||
} else {
|
||||
things.add(thing);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Finally return list of submissions
|
||||
return things;
|
||||
|
||||
} catch (ParseException pe) {
|
||||
throw new RedditParseException(pe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the data into a thing if possible.
|
||||
*
|
||||
* @param kind Kind of data
|
||||
* @param data Data for the thing
|
||||
* @return The thing generated from the data, if failed <i>null</i>
|
||||
*/
|
||||
private Thing parseThing(Kind kind, JSONObject data) {
|
||||
|
||||
// For a comment
|
||||
if (kind == Kind.COMMENT) {
|
||||
return new Comment(data);
|
||||
|
||||
// For a submission
|
||||
} else if (kind == Kind.LINK) {
|
||||
return new Submission(data);
|
||||
|
||||
// For a subreddit
|
||||
} else if (kind == Kind.SUBREDDIT) {
|
||||
return new Subreddit(data);
|
||||
|
||||
// For a more
|
||||
} else if (kind == Kind.MORE) {
|
||||
return new More(data);
|
||||
|
||||
// In all other cases (null, or of a different type)
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.github.jreddit.parser.listing;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.parser.entity.Submission;
|
||||
import com.github.jreddit.parser.entity.Thing;
|
||||
import com.github.jreddit.parser.exception.RedditParseException;
|
||||
|
||||
public class SubmissionsListingParser extends RedditListingParser {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SubmissionsListingParser.class);
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a list of submissions.
|
||||
* This parser expects the JSON to be of a listing of submissions ('links').
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @return Parsed list of submissions
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public List<Submission> parse(String jsonText) throws RedditParseException {
|
||||
|
||||
// Parse to a list of things
|
||||
List<Thing> things = this.parseGeneric(jsonText);
|
||||
|
||||
// List of comment and submission mixed elements
|
||||
List<Submission> submissions = new LinkedList<Submission>();
|
||||
|
||||
// Iterate over things
|
||||
for (Thing t : things) {
|
||||
|
||||
if (t instanceof Submission) {
|
||||
submissions.add((Submission) t);
|
||||
} else {
|
||||
LOGGER.warn("Encountered an unexpected reddit thing (" + t.getKind().value() + "), skipping it.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return resulting comments list
|
||||
return submissions;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.github.jreddit.parser.listing;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.jreddit.parser.entity.Subreddit;
|
||||
import com.github.jreddit.parser.entity.Thing;
|
||||
import com.github.jreddit.parser.exception.RedditParseException;
|
||||
|
||||
public class SubredditsListingParser extends RedditListingParser {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SubredditsListingParser.class);
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a list of subreddits.
|
||||
* This parser expects the JSON to be of a listing of subreddits.
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @return Parsed list of subreddits
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public List<Subreddit> parse(String jsonText) throws RedditParseException {
|
||||
|
||||
// Parse to a list of things
|
||||
List<Thing> things = this.parseGeneric(jsonText);
|
||||
|
||||
// List of comment and submission mixed elements
|
||||
List<Subreddit> subreddits = new LinkedList<Subreddit>();
|
||||
|
||||
// Iterate over things
|
||||
for (Thing t : things) {
|
||||
|
||||
if (t instanceof Subreddit) {
|
||||
subreddits.add((Subreddit) t);
|
||||
} else {
|
||||
LOGGER.warn("Encountered an unexpected reddit thing (" + t.getKind().value() + "), skipping it.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return resulting comments list
|
||||
return subreddits;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
package com.github.jreddit.parser.single;
|
||||
|
||||
import static com.github.jreddit.parser.util.JsonUtils.safeJsonToString;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.github.jreddit.parser.entity.Comment;
|
||||
import com.github.jreddit.parser.entity.Kind;
|
||||
import com.github.jreddit.parser.entity.More;
|
||||
import com.github.jreddit.parser.entity.Submission;
|
||||
import com.github.jreddit.parser.entity.imaginary.CommentTreeElement;
|
||||
import com.github.jreddit.parser.entity.imaginary.FullSubmission;
|
||||
import com.github.jreddit.parser.exception.RedditParseException;
|
||||
import com.github.jreddit.parser.util.JsonUtils;
|
||||
|
||||
public class FullSubmissionParser {
|
||||
|
||||
protected static final JSONParser JSON_PARSER = new JSONParser();
|
||||
|
||||
/**
|
||||
* Parse JSON received from reddit into a full submission.
|
||||
* A full submissions means it has both (a) the submission, and (b) the comment tree.
|
||||
*
|
||||
* @param jsonText JSON Text
|
||||
* @return Full submission
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public FullSubmission parse(String jsonText) throws RedditParseException {
|
||||
|
||||
try {
|
||||
|
||||
// Parse JSON text
|
||||
Object response = JSON_PARSER.parse(jsonText);
|
||||
|
||||
// Validate response
|
||||
validate(response);
|
||||
|
||||
// Create submission (casting with JSON is horrible)
|
||||
JSONObject main = (JSONObject) ((JSONArray) response).get(0);
|
||||
Submission submission = new Submission((JSONObject) ((JSONObject) ((JSONArray)((JSONObject) main.get("data")).get("children")).get(0)).get("data"));
|
||||
|
||||
// Create comment tree
|
||||
JSONObject mainTree = (JSONObject) ((JSONArray) response).get(1);
|
||||
List<CommentTreeElement> commentTree = parseRecursive(mainTree);
|
||||
|
||||
// Return the set of submission and its comment tree
|
||||
return new FullSubmission(submission, commentTree);
|
||||
|
||||
} catch (ParseException pe) {
|
||||
throw new RedditParseException(pe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a JSON object consisting of comments and add them
|
||||
* to the already existing list of comments. This does NOT create
|
||||
* a new comment list.
|
||||
*
|
||||
* @param comments List of comments
|
||||
* @param object JSON Object
|
||||
*/
|
||||
protected List<CommentTreeElement> parseRecursive(JSONObject main) throws RedditParseException {
|
||||
|
||||
List<CommentTreeElement> commentTree = new ArrayList<CommentTreeElement>();
|
||||
|
||||
// Iterate over the comment tree results
|
||||
JSONArray array = (JSONArray) ((JSONObject) main.get("data")).get("children");
|
||||
for (Object element : array) {
|
||||
|
||||
// Get the element
|
||||
JSONObject data = (JSONObject) element;
|
||||
|
||||
// Make sure it is of the correct kind
|
||||
String kind = safeJsonToString(data.get("kind"));
|
||||
|
||||
// If it is a comment
|
||||
if (kind != null && kind.equals(Kind.COMMENT.value())) {
|
||||
|
||||
// Create comment
|
||||
Comment comment = new Comment( (JSONObject) data.get("data") );
|
||||
|
||||
// Retrieve replies
|
||||
Object replies = ((JSONObject) data.get("data")).get("replies");
|
||||
|
||||
// If it is an JSON object
|
||||
if (replies instanceof JSONObject) {
|
||||
comment.setReplies(parseRecursive( (JSONObject) replies ));
|
||||
|
||||
// If there are no replies, end with an empty one
|
||||
} else {
|
||||
comment.setReplies(new ArrayList<CommentTreeElement>());
|
||||
}
|
||||
|
||||
// Add comment to the tree
|
||||
commentTree.add(comment);
|
||||
}
|
||||
|
||||
// If it is a more
|
||||
if (kind != null && kind.equals(Kind.MORE.value())) {
|
||||
|
||||
// Add to comment tree
|
||||
commentTree.add(new More((JSONObject) data.get("data")));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return commentTree;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that it is in fact a full submission.
|
||||
*
|
||||
* @param response Object from the JSON parser
|
||||
*
|
||||
* @throws RedditRequestException If the JSON is in incorrect format
|
||||
*/
|
||||
public void validate(Object response) throws RedditParseException {
|
||||
|
||||
// Check for null
|
||||
if (response == null) {
|
||||
throw new RedditParseException();
|
||||
}
|
||||
|
||||
// Check it is a JSON response
|
||||
if (response instanceof JSONObject) {
|
||||
|
||||
// Cast to JSON object
|
||||
JSONObject jsonResponse = (JSONObject) response;
|
||||
|
||||
// Check for error
|
||||
if (jsonResponse.get("error") != null) {
|
||||
throw new RedditParseException(JsonUtils.safeJsonToInteger(jsonResponse.get("error")));
|
||||
} else {
|
||||
throw new RedditParseException("invalid json format, started with object (should start with array)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// It must start with an array
|
||||
if (!(response instanceof JSONArray)) {
|
||||
throw new RedditParseException("invalid json format, did not start with array");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package com.github.jreddit.parser.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.github.jreddit.parser.entity.Comment;
|
||||
import com.github.jreddit.parser.entity.imaginary.CommentTreeElement;
|
||||
|
||||
public class CommentTreeUtils {
|
||||
|
||||
private CommentTreeUtils() {
|
||||
// Empty to disallow the invocation of the default constructor for this utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten the comment tree.
|
||||
* The original comment tree is not overwritten.
|
||||
*
|
||||
* @param cs List of comments that you get returned from one of the other methods here
|
||||
*
|
||||
* @return Flattened comment tree.
|
||||
*/
|
||||
public static List<CommentTreeElement> flattenCommentTree(List<CommentTreeElement> commentTree) {
|
||||
List<CommentTreeElement> target = new ArrayList<CommentTreeElement>();
|
||||
flattenCommentTree(commentTree, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten the comment tree.
|
||||
* The original comment tree is not overwritten.
|
||||
*
|
||||
* @param cs List of comments that you get returned from one of the other methods here
|
||||
* @param target List in which to place the flattened comment tree.
|
||||
*/
|
||||
private static void flattenCommentTree(List<CommentTreeElement> commentTree, List<CommentTreeElement> target) {
|
||||
for (CommentTreeElement c : commentTree) {
|
||||
target.add(c);
|
||||
if (c instanceof Comment) {
|
||||
flattenCommentTree(((Comment)c).getReplies(), target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get printable version of the given comment tree.
|
||||
*
|
||||
* @param cs List of comment tree elements
|
||||
*
|
||||
* @return Printable comment tree
|
||||
*/
|
||||
public static String printCommentTree(List<CommentTreeElement> cs) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (CommentTreeElement c : cs) {
|
||||
builder.append(printCommentTree(c, 0));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get printable version of a comment at a specific level.<br>
|
||||
* <br>
|
||||
* <i>Note: uses unsafe recursion</i>
|
||||
*
|
||||
* @param c Comment
|
||||
* @param level Level to place at
|
||||
*
|
||||
* @return Printable comment tree
|
||||
*/
|
||||
private static String printCommentTree(CommentTreeElement c, int level) {
|
||||
|
||||
// Initialize empty buffer
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
// Add tabulation
|
||||
for (int i = 0; i < level; i++) {
|
||||
builder.append("\t");
|
||||
}
|
||||
|
||||
// Comment string
|
||||
builder.append(c.toString());
|
||||
builder.append("\n");
|
||||
|
||||
// Iterate over children
|
||||
if (c instanceof Comment) {
|
||||
for (CommentTreeElement child : ((Comment) c).getReplies()) {
|
||||
builder.append(printCommentTree(child, level + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Return the buffer
|
||||
return builder.toString();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.github.jreddit.parser.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Safe utilities (not throwing exceptions) for the conversion of JSON
|
||||
* data into basic types such as Integer, Boolean, Long, and Double.
|
||||
*/
|
||||
public final class JsonUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtils.class);
|
||||
|
||||
private JsonUtils() {
|
||||
// forbid creating JsonUtils instance
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts an object into string (used because sometimes JSONObject's get() method returns null).
|
||||
*
|
||||
* @param obj The object to convert.
|
||||
* @return The string.
|
||||
*/
|
||||
public static String safeJsonToString(Object obj) {
|
||||
return obj == null ? null : obj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts an object into an integer
|
||||
*
|
||||
* @param obj The object to convert.
|
||||
* @return an Integer representing the integer value of the Object (null if the object cannot be converted to an Integer)
|
||||
*/
|
||||
public static Integer safeJsonToInteger(Object obj) {
|
||||
Integer intValue = null;
|
||||
|
||||
try {
|
||||
String str = safeJsonToString(obj);
|
||||
intValue = str != null ? Integer.parseInt(str) : null;
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Safe JSON conversion to Integer failed", e);
|
||||
}
|
||||
|
||||
return intValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts an object into an double
|
||||
*
|
||||
* @param obj The object to convert.
|
||||
* @return a Double representing the double value of the Object (null if the object cannot be converted to Double)
|
||||
*/
|
||||
public static Double safeJsonToDouble(Object obj) {
|
||||
Double doubleValue = null;
|
||||
|
||||
try {
|
||||
String str = safeJsonToString(obj);
|
||||
doubleValue = str != null ? Double.parseDouble(str) : null;
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Safe JSON conversion to Double failed", e);
|
||||
}
|
||||
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Safely converts an object into an boolean
|
||||
*
|
||||
* @param obj The object to convert.
|
||||
* @return a Boolean representing the boolean value of the Object (null only if the object was also null)
|
||||
*/
|
||||
public static Boolean safeJsonToBoolean(Object obj) {
|
||||
String str = safeJsonToString(obj);
|
||||
Boolean booleanValue = str != null ? Boolean.parseBoolean(str) : null;
|
||||
return booleanValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely converts an object into an long
|
||||
*
|
||||
* @param obj The object to convert.
|
||||
* @return a Long representing the long value of the Object (null if the object cannot be converted to Long)
|
||||
*/
|
||||
public static Long safeJsonToLong(Object obj) {
|
||||
Long longValue = null;
|
||||
|
||||
try {
|
||||
String str = safeJsonToString(obj);
|
||||
longValue = str != null ? Long.parseLong(str) : null;
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("Safe JSON conversion to Long failed", e);
|
||||
}
|
||||
|
||||
return longValue;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.github.jreddit.request;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.jreddit.request.util.KeyValueFormatter;
|
||||
|
||||
public abstract class RedditGetRequest {
|
||||
|
||||
/** Mapping of all request parameters. */
|
||||
private Map<String, String> parameters;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public RedditGetRequest() {
|
||||
parameters = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a parameter to the request.
|
||||
* If the key of the parameter already exists, the previous value will be overwritten.
|
||||
*
|
||||
* @param key Key of the parameter (e.g. "limit")
|
||||
* @param value Value of the parameter (e.g. "100")
|
||||
*/
|
||||
protected void addParameter(String key, String value) {
|
||||
parameters.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the query parameters to be added to an URL.
|
||||
*
|
||||
* @return Parameters (e.g. "limit=100&sort=top")
|
||||
*/
|
||||
protected String generateParameters() {
|
||||
return KeyValueFormatter.format(parameters, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the URI of the request.
|
||||
* Be sure to call {@link #generateParameters()} to add the parameters to the end of the URL.
|
||||
*
|
||||
* @return Reddit Uniform Resource Identifier (e.g. "/usr/endpoint?limit=100&sort=top")
|
||||
*/
|
||||
public abstract String generateRedditURI();
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.github.jreddit.request;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.jreddit.request.util.KeyValueFormatter;
|
||||
|
||||
public abstract class RedditPostRequest {
|
||||
|
||||
/** Mapping of all request query parameters. */
|
||||
private Map<String, String> queryParameters;
|
||||
|
||||
/** Mapping of all request body parameters. */
|
||||
private Map<String, String> bodyParameters;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public RedditPostRequest() {
|
||||
queryParameters = new HashMap<String, String>();
|
||||
bodyParameters = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a parameter to the query of the request.
|
||||
* If the key of the parameter already exists, the previous value will be overwritten.
|
||||
*
|
||||
* @param key Key of the parameter (e.g. "limit")
|
||||
* @param value Value of the parameter (e.g. "100")
|
||||
*/
|
||||
protected void addQueryParameter(String key, String value) {
|
||||
queryParameters.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a parameter to the body of the request.
|
||||
* If the key of the parameter already exists, the previous value will be overwritten.
|
||||
*
|
||||
* @param key Key of the parameter (e.g. "id")
|
||||
* @param value Value of the parameter (e.g. "dajkjsf8")
|
||||
*/
|
||||
protected void addBodyParameter(String key, String value) {
|
||||
bodyParameters.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the query parameters to be added to an URI.<br>
|
||||
* <br>
|
||||
* <i>Note: values are encoded.</i>
|
||||
*
|
||||
* @return Query parameters (e.g. "limit=100&sort=top")
|
||||
*/
|
||||
protected String generateQueryParameters() {
|
||||
return KeyValueFormatter.format(queryParameters, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the body parameters to be added.<br>
|
||||
* <br>
|
||||
* <i>Note: values are encoded.</i>
|
||||
*
|
||||
* @return Body parameters (e.g. "limit=100&sort=top")
|
||||
*/
|
||||
protected String generateBodyParameters() {
|
||||
return KeyValueFormatter.format(bodyParameters, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the URI of the request.
|
||||
* Be sure to call {@link #generateQueryParameters()} in your implementation
|
||||
* to add the parameters to the end of the URL.
|
||||
*
|
||||
* @return Reddit Uniform Resource Identifier (e.g. "/usr/endpoint?limit=100&sort=top")
|
||||
*/
|
||||
public abstract String generateRedditURI();
|
||||
|
||||
/**
|
||||
* Generate the body for a POST request using the POST parameters.
|
||||
|
||||
* @return Body (e.g. "limit=100&sort=top" for parameters limit: 100 and sort: "top")
|
||||
*/
|
||||
public String generateBody() {
|
||||
return generateBodyParameters();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.github.jreddit.request.action;
|
||||
|
||||
import com.github.jreddit.request.RedditPostRequest;
|
||||
|
||||
public abstract class MarkActionRequest extends RedditPostRequest {
|
||||
|
||||
/**
|
||||
* Action request.
|
||||
*
|
||||
* @param fullname The fullname of the target (e.g. "t3_djkfsjka")
|
||||
*/
|
||||
public MarkActionRequest(String fullname) {
|
||||
this.addBodyParameter("id", fullname);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.github.jreddit.request.action.flair;
|
||||
|
||||
import com.github.jreddit.request.RedditPostRequest;
|
||||
|
||||
public class DeleteFlairRequest extends RedditPostRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/deleteflair.json?";
|
||||
|
||||
public DeleteFlairRequest(String username) {
|
||||
this.addBodyParameter("name", username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class HideRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/hide.json?";
|
||||
|
||||
public HideRequest(String fullname) {
|
||||
super(fullname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class MarkNsfwRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/marknsfw.json?";
|
||||
|
||||
public MarkNsfwRequest(String fullname) {
|
||||
super(fullname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class ReportRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/report.json?";
|
||||
|
||||
public ReportRequest(String fullname) {
|
||||
super(fullname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class SaveRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/save.json?";
|
||||
|
||||
public SaveRequest(String fullname) {
|
||||
super(fullname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class UnhideRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/unhide.json?";
|
||||
|
||||
public UnhideRequest(String fullname) {
|
||||
super(fullname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class UnmarkNsfwRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/unmarknsfw.json?";
|
||||
|
||||
public UnmarkNsfwRequest(String fullname) {
|
||||
super(fullname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class UnsaveRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/unsave.json?";
|
||||
|
||||
public UnsaveRequest(String fullname) {
|
||||
super(fullname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.github.jreddit.request.action.mark;
|
||||
|
||||
import com.github.jreddit.request.action.MarkActionRequest;
|
||||
|
||||
|
||||
public class VoteRequest extends MarkActionRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/vote.json?";
|
||||
|
||||
/**
|
||||
* Vote request constructor.
|
||||
*
|
||||
* @param fullname Fullname of what to vote on
|
||||
* @param direction Direction (must be -1, 0, or 1)
|
||||
*/
|
||||
public VoteRequest(String fullname, int direction) {
|
||||
super(fullname);
|
||||
this.addBodyParameter("dir", String.valueOf(direction));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return ENDPOINT_FORMAT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.github.jreddit.request.retrieval;
|
||||
|
||||
import com.github.jreddit.parser.entity.Thing;
|
||||
import com.github.jreddit.request.RedditGetRequest;
|
||||
|
||||
public abstract class ListingRequest extends RedditGetRequest {
|
||||
|
||||
/**
|
||||
* @param count Starting count for first element of listing
|
||||
* @return This request
|
||||
*/
|
||||
public ListingRequest setCount(int count) {
|
||||
this.addParameter("count", String.valueOf(count));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param limit Maximum number of listing elements. This does not mean exactly this parameter will be returned. An upper bound (~100) is imposed by reddit.
|
||||
* @return This request
|
||||
*/
|
||||
public ListingRequest setLimit(int limit) {
|
||||
this.addParameter("limit", String.valueOf(limit));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param after The thing in a listing after which the newly requested listing should start.
|
||||
* @return This request
|
||||
*/
|
||||
public ListingRequest setAfter(Thing after) {
|
||||
return setAfter(after.getFullName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param after The fullname of a thing in a listing after which the newly requested listing should start.
|
||||
* @return This request
|
||||
* @see ListingRequest#setAfter(Thing) The usage of setAfter(Thing) is preferred over this method
|
||||
*/
|
||||
public ListingRequest setAfter(String after) {
|
||||
this.addParameter("after", after);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param before The thing in a listing before which the newly requested listing should end.
|
||||
* @return This request
|
||||
*/
|
||||
public ListingRequest setBefore(Thing before) {
|
||||
return setBefore(before.getFullName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param before The fullname of a thing in a listing before which the newly requested listing should end.
|
||||
* @return This request
|
||||
* @see ListingRequest#setBefore(Thing) The usage of setBefore(Thing) is preferred over this method
|
||||
*/
|
||||
public ListingRequest setBefore(String before) {
|
||||
this.addParameter("before", before);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.github.jreddit.request.retrieval.comments;
|
||||
|
||||
import com.github.jreddit.request.retrieval.ListingRequest;
|
||||
import com.github.jreddit.request.retrieval.param.TimeSpan;
|
||||
import com.github.jreddit.request.retrieval.param.UserOverviewSort;
|
||||
|
||||
public class CommentsOfUserRequest extends ListingRequest {
|
||||
|
||||
private static final String ENDPOINT_FORMAT = "/user/%s/comments.json?%s";
|
||||
|
||||
String username;
|
||||
|
||||
/**
|
||||
* @param username Username of a user (e.g. "JohnM")
|
||||
*/
|
||||
public CommentsOfUserRequest(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public CommentsOfUserRequest setSort(UserOverviewSort sort) {
|
||||
this.addParameter("sort", sort.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommentsOfUserRequest setShowGiven() {
|
||||
this.addParameter("show", "given");
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommentsOfUserRequest setTime(TimeSpan time) {
|
||||
this.addParameter("t", time.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, username, this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.github.jreddit.request.retrieval.comments;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.github.jreddit.request.RedditGetRequest;
|
||||
import com.github.jreddit.request.retrieval.param.CommentSort;
|
||||
import com.github.jreddit.request.util.KeyValueFormatter;
|
||||
|
||||
public class MoreCommentsRequest extends RedditGetRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/api/morechildren.json?%s";
|
||||
|
||||
/**
|
||||
* @param submissionFullname Fullname of the submission (e.g. "t3_dajdkjf")
|
||||
* @param commentIdentifiers List of comment ID36 identifiers (e.g. ["jdafid9", "jdafid10"])
|
||||
*
|
||||
* @see {@link com.github.jreddit.parser.entity.More#getChildren()} is typically used to retrieve the 2nd parameter
|
||||
*/
|
||||
public MoreCommentsRequest(String submissionFullname, List<String> commentIdentifiers) {
|
||||
// Neglected optional "id" parameter, as it is only relevant for HTML
|
||||
this.addParameter("api_type", "json");
|
||||
this.addParameter("link_id", submissionFullname);
|
||||
this.addParameter("children", KeyValueFormatter.formatCommaSeparatedList(commentIdentifiers));
|
||||
}
|
||||
|
||||
public MoreCommentsRequest setSort(CommentSort sort) {
|
||||
this.addParameter("sort", sort.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.github.jreddit.request.retrieval.mixed;
|
||||
|
||||
import com.github.jreddit.parser.entity.Comment;
|
||||
import com.github.jreddit.parser.entity.Submission;
|
||||
import com.github.jreddit.request.RedditGetRequest;
|
||||
import com.github.jreddit.request.retrieval.param.CommentSort;
|
||||
|
||||
public class FullSubmissionRequest extends RedditGetRequest {
|
||||
|
||||
private static final String ENDPOINT_FORMAT = "/comments/%s.json?%s";
|
||||
|
||||
private String submissionIdentifier;
|
||||
|
||||
/**
|
||||
* @param submissionIdentifier Submission ID36 identifier (e.g. "dfjIuf")
|
||||
*
|
||||
* @see {@link FullSubmissionRequest(Submission)} is preferred over this constructor
|
||||
*/
|
||||
public FullSubmissionRequest(String submissionIdentifier) {
|
||||
this.submissionIdentifier = submissionIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param submission Submission ID36 identifier (e.g. "dfjIuf")
|
||||
*/
|
||||
public FullSubmissionRequest(Submission submission) {
|
||||
this(submission.getIdentifier());
|
||||
}
|
||||
|
||||
public FullSubmissionRequest setSort(CommentSort sort) {
|
||||
this.addParameter("sort", sort.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public FullSubmissionRequest setLimit(int limit) {
|
||||
this.addParameter("limit", String.valueOf(limit));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the comment that will be the (highlighted) focal point of the
|
||||
* returned view and <i>context</i> will be the number of parents shown.
|
||||
*
|
||||
* @param commentIdentifier Comment ID36 identifier
|
||||
*
|
||||
* @return This builder
|
||||
*
|
||||
* @see Comment#getIdentifier()
|
||||
* @see {@link #setContext(int)}
|
||||
*/
|
||||
public FullSubmissionRequest setComment(String commentIdentifier) {
|
||||
this.addParameter("comment", commentIdentifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of parents shown. This will only affect the result if
|
||||
* {@link #setComment(String)} has been set.
|
||||
*
|
||||
* @param context Maximum number of parents shown (integer between 0 and 8)
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public FullSubmissionRequest setContext(int context) {
|
||||
this.addParameter("context", String.valueOf(context));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum depth of subtrees in the thread.
|
||||
*
|
||||
* @param depth An integer indicating maximum depth
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public FullSubmissionRequest setDepth(int depth) {
|
||||
this.addParameter("depth", String.valueOf(depth));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to show the edits in the comments.
|
||||
*
|
||||
* @param showEdits Should the edits be shown?
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public FullSubmissionRequest setShowEdits(boolean showEdits) {
|
||||
this.addParameter("showedits", String.valueOf(showEdits));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the "more" buttons should be shown.
|
||||
*
|
||||
* @param showMore Should the more buttons be shown?
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public FullSubmissionRequest setShowMore(boolean showMore) {
|
||||
this.addParameter("showmore", String.valueOf(showMore));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, submissionIdentifier, this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.github.jreddit.request.retrieval.mixed;
|
||||
|
||||
import com.github.jreddit.request.retrieval.ListingRequest;
|
||||
import com.github.jreddit.request.retrieval.param.TimeSpan;
|
||||
import com.github.jreddit.request.retrieval.param.UserMixedCategory;
|
||||
import com.github.jreddit.request.retrieval.param.UserOverviewSort;
|
||||
|
||||
public class MixedOfUserRequest extends ListingRequest {
|
||||
|
||||
/** Endpoint format. */
|
||||
private static final String ENDPOINT_FORMAT = "/user/%s/%s.json?%s";
|
||||
|
||||
private UserMixedCategory category;
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* @param username Username of a user (e.g. "JohnM")
|
||||
* @param category Category of mixed things
|
||||
*/
|
||||
public MixedOfUserRequest(String username, UserMixedCategory category) {
|
||||
this.username = username;
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sorting method.<br>
|
||||
* <br>
|
||||
* <i>Note: This only works for Overview</i>
|
||||
*
|
||||
* @param sort Sorting method
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public MixedOfUserRequest setSort(UserOverviewSort sort) {
|
||||
this.addParameter("sort", sort.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time span.<br>
|
||||
* <br>
|
||||
* <i>Note: This only works for Overview, and then specifically for the top/controversial sorting method.</i>
|
||||
*
|
||||
* @param time Time span
|
||||
*
|
||||
* @return This builder
|
||||
*/
|
||||
public MixedOfUserRequest setTime(TimeSpan time) {
|
||||
this.addParameter("t", time.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public MixedOfUserRequest setShowGiven() {
|
||||
this.addParameter("show", "given");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, username, category.value(), this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
/**
|
||||
* Enum to represent comment sorts on Reddit. You see these on a page that lists comments.
|
||||
*
|
||||
* @author Evin Ugur
|
||||
* @author Raul Rene Lepsa
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum CommentSort {
|
||||
|
||||
CONFIDENCE("confidence"),
|
||||
NEW("new"),
|
||||
TOP("top"),
|
||||
CONTROVERSIAL("controversial"),
|
||||
OLD("old"),
|
||||
QA("qa");
|
||||
|
||||
private final String value;
|
||||
|
||||
CommentSort(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
/**
|
||||
* Enum to represent the possible query syntaxes.
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum QuerySyntax {
|
||||
|
||||
CLOUDSEARCH ("cloudsearch"),
|
||||
LUCENE ("lucene"),
|
||||
PLAIN ("plain");
|
||||
|
||||
private final String value;
|
||||
|
||||
QuerySyntax(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
/**
|
||||
* Enumeration to represent the different sort methods for submission search.
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum SearchSort {
|
||||
|
||||
HOT("hot"),
|
||||
RELEVANCE("relevance"),
|
||||
NEW("new"),
|
||||
TOP("top"),
|
||||
COMMENTS("comments");
|
||||
|
||||
private final String value;
|
||||
|
||||
SearchSort(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
/**
|
||||
* Enum to represent submission sorts on Reddit. You see these on a page that lists Submissions.
|
||||
*
|
||||
* @author Evin Ugur
|
||||
* @author Raul Rene Lepsa
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum SubmissionSort {
|
||||
|
||||
HOT("hot"),
|
||||
NEW("new"),
|
||||
RISING("rising"),
|
||||
CONTROVERSIAL("controversial"),
|
||||
TOP("top");
|
||||
|
||||
private final String value;
|
||||
|
||||
SubmissionSort(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
/**
|
||||
* Enumeration to represent the different subreddit categories.
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum SubredditsView {
|
||||
|
||||
NEW("new"),
|
||||
POPULAR("popular"),
|
||||
MINE_SUBSCRIBER("mine/subscriber"),
|
||||
MINE_CONTRIBUTOR("mine/contributor"),
|
||||
MINE_MODERATOR("mine/moderator");
|
||||
|
||||
private final String value;
|
||||
|
||||
SubredditsView(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
/**
|
||||
* Enumeration to represent the different submission search times.
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum TimeSpan {
|
||||
|
||||
HOUR("hour"),
|
||||
DAY("day"),
|
||||
WEEK("week"),
|
||||
MONTH("month"),
|
||||
YEAR("year"),
|
||||
ALL("all");
|
||||
|
||||
private final String value;
|
||||
|
||||
TimeSpan(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
public enum UserMixedCategory {
|
||||
|
||||
OVERVIEW("overview"),
|
||||
GILDED_RECEIVED("gilded"),
|
||||
GILDED_GIVEN("gilded/given"),
|
||||
SAVED("saved");
|
||||
|
||||
private final String value;
|
||||
|
||||
UserMixedCategory(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
/**
|
||||
* Enumeration to represent the different sort methods for the user overview.
|
||||
* @author Simon Kassing
|
||||
*/
|
||||
public enum UserOverviewSort {
|
||||
|
||||
NEW("new"),
|
||||
HOT("hot"),
|
||||
TOP("top"),
|
||||
COMMENTS("controversial");
|
||||
|
||||
private final String value;
|
||||
|
||||
UserOverviewSort(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.github.jreddit.request.retrieval.param;
|
||||
|
||||
public enum UserSubmissionsCategory {
|
||||
|
||||
SUBMITTED("submitted"),
|
||||
UPVOTED("upvoted"),
|
||||
DOWNVOTED("downvoted"),
|
||||
HIDDEN("hidden");
|
||||
|
||||
private final String value;
|
||||
|
||||
UserSubmissionsCategory(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.github.jreddit.request.retrieval.submissions;
|
||||
|
||||
import com.github.jreddit.request.retrieval.ListingRequest;
|
||||
import com.github.jreddit.request.retrieval.param.SubmissionSort;
|
||||
|
||||
public class SubmissionsOfSubredditRequest extends ListingRequest {
|
||||
|
||||
private static final String ENDPOINT_FORMAT = "/r/%s/%s.json?%s";
|
||||
|
||||
private SubmissionSort sort;
|
||||
private String subreddit;
|
||||
|
||||
/**
|
||||
* @param subreddit Subreddit (e.g. "funny")
|
||||
* @param sort Sorting method
|
||||
*/
|
||||
public SubmissionsOfSubredditRequest(String subreddit, SubmissionSort sort) {
|
||||
this.subreddit = subreddit;
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
public SubmissionsOfSubredditRequest setShowAll() {
|
||||
this.addParameter("show", "all");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, subreddit, sort.value(), this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.github.jreddit.request.retrieval.submissions;
|
||||
|
||||
import com.github.jreddit.request.retrieval.ListingRequest;
|
||||
import com.github.jreddit.request.retrieval.param.TimeSpan;
|
||||
import com.github.jreddit.request.retrieval.param.UserOverviewSort;
|
||||
import com.github.jreddit.request.retrieval.param.UserSubmissionsCategory;
|
||||
|
||||
public class SubmissionsOfUserRequest extends ListingRequest {
|
||||
|
||||
private static final String ENDPOINT_FORMAT = "/user/%s/%s.json?%s";
|
||||
|
||||
private UserSubmissionsCategory category;
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* @param username Username of a user (e.g. "JohnM")
|
||||
* @param category Category of user submissions
|
||||
*/
|
||||
public SubmissionsOfUserRequest(String username, UserSubmissionsCategory category) {
|
||||
this.username = username;
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public SubmissionsOfUserRequest setSort(UserOverviewSort sort) {
|
||||
this.addParameter("sort", sort.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubmissionsOfUserRequest setTime(TimeSpan time) {
|
||||
this.addParameter("t", time.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubmissionsOfUserRequest setShowGiven() {
|
||||
this.addParameter("show", "given");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, username, category.value(), this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.github.jreddit.request.retrieval.submissions;
|
||||
|
||||
import com.github.jreddit.request.retrieval.ListingRequest;
|
||||
import com.github.jreddit.request.retrieval.param.QuerySyntax;
|
||||
import com.github.jreddit.request.retrieval.param.SearchSort;
|
||||
import com.github.jreddit.request.retrieval.param.TimeSpan;
|
||||
|
||||
public class SubmissionsSearchRequest extends ListingRequest {
|
||||
|
||||
private static final String ENDPOINT_FORMAT = "/search.json?%s";
|
||||
|
||||
/**
|
||||
* @param query Mandatory search query (e.g. "programming Java"), its syntax depends on what is set using {@link #setSyntax(QuerySyntax)}.
|
||||
*/
|
||||
public SubmissionsSearchRequest(String query) {
|
||||
this.addParameter("q", query);
|
||||
}
|
||||
|
||||
public SubmissionsSearchRequest setSyntax(QuerySyntax syntax) {
|
||||
this.addParameter("syntax", syntax.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubmissionsSearchRequest setSort(SearchSort sort) {
|
||||
this.addParameter("sort", sort.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubmissionsSearchRequest setTimeSpan(TimeSpan time) {
|
||||
this.addParameter("t", time.value());
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubmissionsSearchRequest setShowAll() {
|
||||
this.addParameter("show", "all");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.github.jreddit.request.retrieval.subreddits;
|
||||
|
||||
import com.github.jreddit.request.retrieval.ListingRequest;
|
||||
import com.github.jreddit.request.retrieval.param.SubredditsView;
|
||||
|
||||
public class SubredditsOfUserRequest extends ListingRequest {
|
||||
|
||||
private static final String ENDPOINT_FORMAT = "/subreddits/%s.json?%s"; // ApiEndpointUtils.SUBREDDITS_GET
|
||||
|
||||
private SubredditsView view;
|
||||
|
||||
/**
|
||||
* @param view View of the subreddits
|
||||
*/
|
||||
public SubredditsOfUserRequest(SubredditsView view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public SubredditsOfUserRequest setShowAll() {
|
||||
this.addParameter("show", "all");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, view, this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.github.jreddit.request.retrieval.subreddits;
|
||||
|
||||
import com.github.jreddit.request.retrieval.ListingRequest;
|
||||
|
||||
public class SubredditsSearchRequest extends ListingRequest {
|
||||
|
||||
private static final String ENDPOINT_FORMAT = "/subreddits/search.json?%s";
|
||||
|
||||
/**
|
||||
* @param query Search query (e.g. "programming")
|
||||
*/
|
||||
public SubredditsSearchRequest(String query) {
|
||||
this.addParameter("q", query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRedditURI() {
|
||||
return String.format(ENDPOINT_FORMAT, this.generateParameters());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.github.jreddit.request.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class KeyValueFormatter {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KeyValueFormatter.class);
|
||||
|
||||
private KeyValueFormatter() {
|
||||
// Left empty to prevent instantiation of this utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a mapping of key-value pairs to a string, separating key from value using an
|
||||
* equals (=) sign, and separating pairs using an ampersand (&) sign.
|
||||
*
|
||||
* @param keyValueParameters Mapping of key-value pairs
|
||||
* @param encodeUTF8 Whether or not the values should be encoded in UTF-8
|
||||
*
|
||||
* @return Formatted string of key-value pairs (e.g. "a=1&b=something")
|
||||
*/
|
||||
public static String format(Map<String, String> keyValueParameters, boolean encodeUTF8) {
|
||||
|
||||
// Key set
|
||||
Set<String> keys = keyValueParameters.keySet();
|
||||
|
||||
// Iterate over keys
|
||||
String paramsString = "";
|
||||
boolean start = true;
|
||||
for (String key : keys) {
|
||||
|
||||
// Add separation ampersand
|
||||
if (!start) {
|
||||
paramsString = paramsString.concat("&");
|
||||
} else {
|
||||
start = false;
|
||||
}
|
||||
|
||||
// Retrieve value
|
||||
String value = keyValueParameters.get(key);
|
||||
|
||||
// Encode key
|
||||
if (encodeUTF8) {
|
||||
try {
|
||||
value = URLEncoder.encode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOGGER.warn("Unsupported Encoding Exception thrown when encoding value", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Add key-value pair
|
||||
paramsString = paramsString.concat(key + "=" + value);
|
||||
|
||||
}
|
||||
|
||||
// Return final parameter string
|
||||
return paramsString;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a comma separated list of the given list.
|
||||
*
|
||||
* @param list List of strings
|
||||
*
|
||||
* @return Comma-separated list string (e.g. "a,b,c,d")
|
||||
*/
|
||||
public static String formatCommaSeparatedList(List<String> list) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (i != 0) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append(list.get(i));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,12 @@
|
||||
package sh.adb.RandomRedditMemesAPI;
|
||||
|
||||
public class RedditAPI {
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.github.jreddit.oauth.RedditOAuthAgent;
|
||||
import com.github.jreddit.oauth.RedditToken;
|
||||
import com.github.jreddit.oauth.app.RedditApp;
|
||||
import com.github.jreddit.oauth.app.RedditInstalledApp;
|
||||
import com.github.jreddit.oauth.exception.RedditOAuthException;
|
||||
|
||||
}
|
||||
public class RedditAPI {
|
||||
}
|
||||
|
Loading…
Reference in New Issue