Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patreon API v2 #53

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ Step 2. Use this library
---

## For the Log In with Patreon flow

```java
import com.github.jasminb.jsonapi.JSONAPIDocument;
import com.patreon.PatreonAPI;
import com.patreon.PatreonOAuth;
import com.patreon.PatreonOAuth;
import com.patreon.resources.User;
import com.patreon.resources.Pledge;
import com.patreon.resources.v1.User;
import com.patreon.resources.v1.Pledge;

...

Expand All @@ -48,12 +49,18 @@ String accessToken = tokens.getAccessToken();
PatreonAPI apiClient = new PatreonAPI(accessToken);
JSONAPIDocument<User> userResponse = apiClient.fetchUser();
User user = userResponse.get();
Log.i(user.getFullName());
Log.

i(user.getFullName());
List<Pledge> pledges = user.getPledges()
if (pledges != null && pledges.size() > 0) {
Pledge pledge = pledges.get(0);
Log.i(pledge.getAmountCents());
}
if(pledges !=null&&pledges.

size() >0){
Pledge pledge = pledges.get(0);
Log.

i(pledge.getAmountCents());
}
// You should save the user's PatreonOAuth.TokensResponse in your database
// (for refreshing their Patreon data whenever you like),
// along with any relevant user info or pledge info you want to store.
Expand Down
127 changes: 108 additions & 19 deletions src/main/java/com/patreon/PatreonAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.github.jasminb.jsonapi.*;
import com.patreon.resources.Campaign;
import com.patreon.resources.Pledge;
import com.patreon.resources.RequestUtil;
import com.patreon.resources.User;
import com.patreon.resources.shared.BaseResource;
import com.patreon.resources.shared.Field;
import com.patreon.resources.v1.Campaign;
import com.patreon.resources.v1.Pledge;
import com.patreon.resources.v1.RequestUtil;
import com.patreon.resources.v1.User;
import com.patreon.resources.v2.CampaignV2;
import com.patreon.resources.v2.Member;
import com.patreon.resources.v2.Tier;
import com.patreon.resources.v2.UserV2;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.client.utils.URLEncodedUtils;
Expand Down Expand Up @@ -58,12 +62,81 @@ public PatreonAPI(String accessToken) {
this.converter = new ResourceConverter(
objectMapper,
User.class,
UserV2.class,
Campaign.class,
Pledge.class
Member.class,
CampaignV2.class,
Pledge.class,
Tier.class
);
this.converter.enableDeserializationOption(DeserializationFeature.ALLOW_UNKNOWN_INCLUSIONS);
}

public JSONAPIDocument<UserV2> v2FetchIdentity() throws IOException {
URIBuilder pathBuilder = new URIBuilder()
.setPath("v2/identity")
.addParameter("include", "campaign");
addFieldsParam(pathBuilder, UserV2.class, UserV2.UserField.getDefaultFields());
addFieldsParam(pathBuilder, CampaignV2.class, CampaignV2.CampaignField.getDefaultFields());
return converter.readDocument(
getDataStream(pathBuilder.toString()),
UserV2.class
);
}

public JSONAPIDocument<List<CampaignV2>> v2FetchCampaigns(Integer count) throws IOException {
URIBuilder pathBuilder = new URIBuilder()
.setPath("v2/campaigns")
.addParameter("page[count]", String.valueOf(count));
addFieldsParam(pathBuilder, CampaignV2.class, CampaignV2.CampaignField.getDefaultFields());
return converter.readDocumentCollection(
getDataStream(pathBuilder.toString()),
CampaignV2.class
);
}

public JSONAPIDocument<CampaignV2> v2FetchCampaign(String campaignId) throws IOException {
URIBuilder pathBuilder = new URIBuilder()
.setPath(String.format("v2/campaigns/%s", campaignId));
addFieldsParam(pathBuilder, CampaignV2.class, CampaignV2.CampaignField.getDefaultFields());
return converter.readDocument(
getDataStream(pathBuilder.toString()),
CampaignV2.class
);
}

public JSONAPIDocument<List<Member>> v2FetchCampaignMembers(String campaignId, Integer count) throws IOException {
// Check count is less than 1000
if (count > 1000) {
throw new IllegalArgumentException("Count must be less than 1000");
}

URIBuilder pathBuilder = new URIBuilder()
.setPath(String.format("v2/campaigns/%s/members", campaignId))
.addParameter("include", "user,currently_entitled_tiers")
.addParameter("page[count]", String.valueOf(count));
addFieldsParam(pathBuilder, Member.class, Member.MemberField.getDefaultFields());
addFieldsParam(pathBuilder, UserV2.class, UserV2.UserField.getDefaultFields());
addFieldsParam(pathBuilder, Tier.class, Tier.TierField.getDefaultFields());
return converter.readDocumentCollection(
getDataStream(pathBuilder.toString()),
Member.class
);
}

public JSONAPIDocument<Member> v2FetchMember(String memberId) throws IOException {
URIBuilder pathBuilder = new URIBuilder()
.setPath(String.format("v2/members/%s", memberId))
.addParameter("include", "user,currently_entitled_tiers");
addFieldsParam(pathBuilder, Member.class, Member.MemberField.getDefaultFields());
addFieldsParam(pathBuilder, UserV2.class, UserV2.UserField.getDefaultFields());
addFieldsParam(pathBuilder, Tier.class, Tier.TierField.getDefaultFields());
return converter.readDocument(
getDataStream(pathBuilder.toString()),
Member.class
);
}

/**
* Get the user object of the creator
*
Expand All @@ -83,8 +156,8 @@ public JSONAPIDocument<User> fetchUser() throws IOException {
*/
public JSONAPIDocument<User> fetchUser(Collection<User.UserField> optionalFields) throws IOException {
URIBuilder pathBuilder = new URIBuilder()
.setPath("current_user")
.addParameter("include", "pledges");
.setPath("api/current_user")
.addParameter("include", "pledges");
if (optionalFields != null) {
Set<User.UserField> optionalAndDefaultFields = new HashSet<>(optionalFields);
optionalAndDefaultFields.addAll(User.UserField.getDefaultFields());
Expand All @@ -106,9 +179,9 @@ public JSONAPIDocument<User> fetchUser(Collection<User.UserField> optionalFields
*/
public JSONAPIDocument<List<Campaign>> fetchCampaigns() throws IOException {
String path = new URIBuilder()
.setPath("current_user/campaigns")
.addParameter("include", "rewards,creator,goals")
.toString();
.setPath("api/current_user/campaigns")
.addParameter("include", "rewards,creator,goals")
.toString();
return converter.readDocumentCollection(
getDataStream(path),
Campaign.class
Expand All @@ -132,18 +205,18 @@ public JSONAPIDocument<List<Pledge>> fetchPageOfPledges(String campaignId, int p
/**
* Retrieve pledges for the specified campaign
*
* @param campaignId id for campaign to retrieve
* @param pageSize how many pledges to return
* @param pageCursor A cursor retreived from a previous API call, or null for the initial page.
* See {@link #getNextCursorFromDocument(JSONAPIDocument)}
* @param campaignId id for campaign to retrieve
* @param pageSize how many pledges to return
* @param pageCursor A cursor retreived from a previous API call, or null for the initial page.
* See {@link #getNextCursorFromDocument(JSONAPIDocument)}
* @param optionalFields A list of optional fields to return. See {@link Pledge.PledgeField}
* @return the page of pledges
* @throws IOException Thrown when the GET request failed
*/
public JSONAPIDocument<List<Pledge>> fetchPageOfPledges(String campaignId, int pageSize, String pageCursor, Collection<Pledge.PledgeField> optionalFields) throws IOException {
URIBuilder pathBuilder = new URIBuilder()
.setPath(String.format("campaigns/%s/pledges", campaignId))
.addParameter("page[count]", String.valueOf(pageSize));
.setPath(String.format("api/campaigns/%s/pledges", campaignId))
.addParameter("page[count]", String.valueOf(pageSize));
if (pageCursor != null) {
pathBuilder.addParameter("page[cursor]", pageCursor);
}
Expand Down Expand Up @@ -183,10 +256,25 @@ public String getNextCursorFromDocument(JSONAPIDocument document) {
}

public List<Pledge> fetchAllPledges(String campaignId) throws IOException {
return fetchAllPledges(campaignId, false);
}

/**
* Retrieve all pledges for the specified campaign
*
* @param campaignId id for campaign to retrieve
* @return the list of pledges
* @throws IOException Thrown when the GET request failed
*/
public List<Pledge> fetchAllPledges(String campaignId, boolean full) throws IOException {
Set<Pledge> pledges = new HashSet<>();
String cursor = null;
Collection<Pledge.PledgeField> fields = null;
if (full) {
fields = Pledge.PledgeField.getAllFields();
}
while (true) {
JSONAPIDocument<List<Pledge>> pledgesPage = fetchPageOfPledges(campaignId, 15, cursor);
JSONAPIDocument<List<Pledge>> pledgesPage = fetchPageOfPledges(campaignId, 15, cursor, fields);
pledges.addAll(pledgesPage.get());
cursor = getNextCursorFromDocument(pledgesPage);
if (cursor == null) {
Expand All @@ -203,9 +291,10 @@ private InputStream getDataStream(String suffix) throws IOException {

/**
* Add fields[type]=fieldName,fieldName,fieldName as a query parameter to the request represented by builder
*
* @param builder A URIBuilder building a request to the API
* @param type A BaseResource annotated with {@link com.github.jasminb.jsonapi.annotations.Type}
* @param fields A list of fields to include. Only fields in this list will be retrieved in the query
* @param type A BaseResource annotated with {@link com.github.jasminb.jsonapi.annotations.Type}
* @param fields A list of fields to include. Only fields in this list will be retrieved in the query
* @return builder
*/
private URIBuilder addFieldsParam(URIBuilder builder, Class<? extends BaseResource> type, Collection<? extends Field> fields) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.patreon.resources;
package com.patreon.resources.v1;


import com.fasterxml.jackson.annotation.JsonProperty;
Expand All @@ -7,7 +7,6 @@
import com.patreon.resources.shared.BaseResource;
import com.patreon.resources.shared.Field;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.patreon.resources;
package com.patreon.resources.v1;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.jasminb.jsonapi.annotations.Type;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package com.patreon.resources;
package com.patreon.resources.v1;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.jasminb.jsonapi.annotations.Relationship;
import com.github.jasminb.jsonapi.annotations.Type;
import com.patreon.resources.shared.BaseResource;
import com.patreon.resources.shared.Field;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Type("pledge")
public class Pledge extends BaseResource {

public enum PledgeField implements Field {
AmountCents("amount_cents", true),
CreatedAt("created_at", true),
Expand All @@ -23,6 +21,7 @@ public enum PledgeField implements Field {
PledgeCapCents("pledge_cap_cents", true),
TotalHistoricalAmountCents("total_historical_amount_cents", false),
IsPaused("is_paused", false),
Status("status", false),
HasShippingAddress("has_shipping_address", false),
;

Expand All @@ -38,6 +37,10 @@ public static Collection<PledgeField> getDefaultFields() {
return Arrays.stream(values()).filter(Field::isDefault).collect(Collectors.toList());
}

public static Collection<PledgeField> getAllFields() {
return Arrays.asList(values());
}

@Override
public String getPropertyName() {
return this.propertyName;
Expand All @@ -49,6 +52,25 @@ public boolean isDefault() {
}
}

public enum PledgeStatus {
valid,
declined,
pending,
disabled,
fraud,
unknown,
;

public static PledgeStatus fromString(String status) {
for (PledgeStatus s : PledgeStatus.values()) {
if (s.toString().equals(status)) {
return s;
}
}
return unknown;
}
}

private int amountCents;
private String createdAt;
private String declinedSince;
Expand All @@ -58,6 +80,7 @@ public boolean isDefault() {
//Optional properties. Will be null if not requested
private Integer totalHistoricalAmountCents;
private Boolean isPaused;
private PledgeStatus status;
private Boolean hasShippingAddress;

@Relationship("creator")
Expand All @@ -70,17 +93,18 @@ public boolean isDefault() {
private Reward reward;

public Pledge(
@JsonProperty("amount_cents") int amount_cents,
@JsonProperty("created_at") String created_at,
@JsonProperty("declined_since") String declined_since,
@JsonProperty("patron_pays_fees") boolean patron_pays_fees,
@JsonProperty("pledge_cap_cents") int pledge_cap_cents,
@JsonProperty("total_historical_amount_cents") Integer total_historical_amount_cents,
@JsonProperty("is_paused") Boolean is_paused,
@JsonProperty("has_shipping_address") Boolean has_shipping_address,
@JsonProperty("creator") User creator,
@JsonProperty("patron") User patron,
@JsonProperty("reward") Reward reward
@JsonProperty("amount_cents") int amount_cents,
@JsonProperty("created_at") String created_at,
@JsonProperty("declined_since") String declined_since,
@JsonProperty("patron_pays_fees") boolean patron_pays_fees,
@JsonProperty("pledge_cap_cents") int pledge_cap_cents,
@JsonProperty("total_historical_amount_cents") Integer total_historical_amount_cents,
@JsonProperty("is_paused") Boolean is_paused,
@JsonProperty("status") String status,
@JsonProperty("has_shipping_address") Boolean has_shipping_address,
@JsonProperty("creator") User creator,
@JsonProperty("patron") User patron,
@JsonProperty("reward") Reward reward
) {
this.amountCents = amount_cents;
this.createdAt = created_at;
Expand All @@ -89,6 +113,7 @@ public Pledge(
this.pledgeCapCents = pledge_cap_cents;
this.totalHistoricalAmountCents = total_historical_amount_cents;
this.isPaused = is_paused;
this.status = PledgeStatus.fromString(status);
this.hasShippingAddress = has_shipping_address;
this.creator = creator;
this.patron = patron;
Expand Down Expand Up @@ -130,6 +155,13 @@ public Boolean getPaused() {
return isPaused;
}

/**
* @return The status of the pledge, or null if this field wasn't requested
*/
public PledgeStatus getStatus() {
return status;
}

/**
* @return Whether this patron has a shipping address, or null if this field wasn't requested
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.patreon.resources;
package com.patreon.resources.v1;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -13,7 +13,7 @@
public class RequestUtil {

public InputStream request(String pathSuffix, String accessToken) throws IOException {
String prefix = BASE_URI + "/api/oauth2/api/";
String prefix = BASE_URI + "/api/oauth2/";
URL url = new URL(prefix.concat(pathSuffix));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Bearer ".concat(accessToken));
Expand Down
Loading