Skip to content

Commit

Permalink
Generic OAuth 2 util
Browse files Browse the repository at this point in the history
  • Loading branch information
VSydor committed Jul 8, 2023
1 parent e62c396 commit 67298e8
Show file tree
Hide file tree
Showing 6 changed files with 482 additions and 383 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
package com.impactupgrade.nucleus.client;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.common.base.Strings;
import com.impactupgrade.nucleus.environment.Environment;
import com.impactupgrade.nucleus.environment.EnvironmentConfig;
import com.impactupgrade.nucleus.model.CrmContact;
import com.impactupgrade.nucleus.util.HttpClient;
import com.impactupgrade.nucleus.util.OAuth2Util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import static com.impactupgrade.nucleus.util.HttpClient.TokenResponse;
import static com.impactupgrade.nucleus.util.HttpClient.get;
import static com.impactupgrade.nucleus.util.HttpClient.post;
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;

// TODO: To eventually become a mbt-java-client open source lib?
Expand All @@ -31,11 +27,15 @@ public class MinistryByTextClient {

protected final Environment env;

protected String accessToken;
protected Calendar accessTokenExpiration;
protected static OAuth2Util.Tokens tokens;

private String clientId;
private String clientSecret;

public MinistryByTextClient(Environment env) {
this.env = env;
this.clientId = env.getConfig().mbt.clientId;
this.clientSecret = env.getConfig().mbt.clientSecret;
}

public List<Group> getGroups(String campusId) {
Expand Down Expand Up @@ -102,37 +102,15 @@ public static class SubscriberRelation {
}

protected HttpClient.HeaderBuilder headers() {
if (isAccessTokenInvalid()) {
log.info("Getting new access token...");
TokenResponse tokenResponse = getAccessToken();
accessToken = tokenResponse.accessToken;
Calendar onehour = Calendar.getInstance();
onehour.add(Calendar.SECOND, tokenResponse.expiresIn);
accessTokenExpiration = onehour;
tokens = OAuth2Util.refreshTokens(tokens, AUTH_ENDPOINT);
if (tokens == null) {
tokens = OAuth2Util.getTokensForClientCredentials(clientId, clientSecret, AUTH_ENDPOINT);
}
System.out.println(accessToken);
String accessToken = tokens != null ? tokens.accessToken() : null;
return HttpClient.HeaderBuilder.builder().authBearerToken(accessToken);
}

protected boolean isAccessTokenInvalid() {
Calendar now = Calendar.getInstance();
return Strings.isNullOrEmpty(accessToken) || now.after(accessTokenExpiration);
}

protected TokenResponse getAccessToken() {
// TODO: Map.of should be able to be used instead of Form (see VirtuousClient), but getting errors about no writer
return post(
AUTH_ENDPOINT,
new Form()
.param("client_id", env.getConfig().mbt.clientId)
.param("client_secret", env.getConfig().mbt.clientSecret)
.param("grant_type", "client_credentials"),
APPLICATION_FORM_URLENCODED,
HttpClient.HeaderBuilder.builder(),
TokenResponse.class
);
}

//TODO: remove once done with testing
public static void main(String[] args) {
Environment env = new Environment() {
@Override
Expand All @@ -153,5 +131,8 @@ public EnvironmentConfig getConfig() {
crmContact.mobilePhone = "260-349-5732";
Subscriber subscriber = mbtClient.upsertSubscriber(crmContact, "c64ecadf-bbfa-4cd4-8f19-a64e5d661b2b");
System.out.println(subscriber);

// To check same access token is used
subscriber = mbtClient.upsertSubscriber(crmContact, "c64ecadf-bbfa-4cd4-8f19-a64e5d661b2b");
}
}
69 changes: 35 additions & 34 deletions src/main/java/com/impactupgrade/nucleus/client/RaiselyClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,32 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.impactupgrade.nucleus.environment.Environment;
import com.impactupgrade.nucleus.util.HttpClient;
import com.impactupgrade.nucleus.util.OAuth2Util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.List;
import java.util.Map;

import static com.impactupgrade.nucleus.util.HttpClient.get;
import static com.impactupgrade.nucleus.util.HttpClient.post;

public class RaiselyClient{
public class RaiselyClient {

private static final Logger log = LogManager.getLogger(RaiselyClient.class);
private static final String RAISELY_API_URL = "https://api.raisely.com/v3/";
private static final String APPLICATION_JSON = "application/json";
private static final String AUTH_URL = RAISELY_API_URL + "login";

protected final Environment env;

private String _accessToken = null;
protected static OAuth2Util.Tokens tokens;

private String username;
private String password;

public RaiselyClient(Environment env){
public RaiselyClient(Environment env) {
this.env = env;
this.username = env.getConfig().raisely.username;
this.password = env.getConfig().raisely.password;
}

//*Note this uses the donation ID from the Stripe metadata. Different from the donation UUID
Expand All @@ -34,7 +40,7 @@ public RaiselyClient(Environment env){
* like this: https://api.raisely.com/v3/donations?idGTE=14619704&idLTE=14619704&private=true
*/

public RaiselyClient.Donation getDonation(String donationId){
public RaiselyClient.Donation getDonation(String donationId) {
DonationResponse response = get(
RAISELY_API_URL + "donations?idGTE=" + donationId + "&idLTE=" + donationId + "&private=true",
HttpClient.HeaderBuilder.builder().authBearerToken(getAccessToken()),
Expand All @@ -49,27 +55,14 @@ public RaiselyClient.Donation getDonation(String donationId){
}

protected String getAccessToken() {
if (_accessToken == null) {
String username = env.getConfig().raisely.username;
String password = env.getConfig().raisely.password;

log.info("Getting token...");
HttpClient.HeaderBuilder headers = HttpClient.HeaderBuilder.builder();
TokenResponse response = post(RAISELY_API_URL + "login", Map.of("requestAdminToken", "true", "username", username, "password", password), APPLICATION_JSON, headers, TokenResponse.class);
log.info("Token: {}", response.token);
this._accessToken = response.token;
tokens = OAuth2Util.refreshTokens(tokens, AUTH_URL);
if (tokens == null) {
tokens = OAuth2Util.getTokensForUsernameAndPassword(username, password, AUTH_URL);
}

return this._accessToken;
return tokens != null ? tokens.accessToken() : null;
}

//Response Objects
@JsonIgnoreProperties(ignoreUnknown = true)
public static class TokenResponse {
@JsonProperty("token")
public String token;
}

@JsonIgnoreProperties(ignoreUnknown = true)
public static class DonationResponse {
public List<Donation> data;
Expand All @@ -94,12 +87,12 @@ public static class Donation {
@Override
public String toString() {
return "Donation{" +
"amount=" + amount +
", fee=" + fee +
", feeOptIn = " + feeCovered +
", total='" + total + '\'' +
", items='" + items + '\'' +
'}';
"amount=" + amount +
", fee=" + fee +
", feeOptIn = " + feeCovered +
", total='" + total + '\'' +
", items='" + items + '\'' +
'}';
}
}

Expand All @@ -113,13 +106,21 @@ public static class DonationItem {
@Override
public String toString() {
return "Item{" +
"amount=" + amount +
", amountRefunded=" + amountRefunded +
", type='" + type + '\'' +
", quantity='" + quantity + '\'' +
'}';
"amount=" + amount +
", amountRefunded=" + amountRefunded +
", type='" + type + '\'' +
", quantity='" + quantity + '\'' +
'}';
}
}

//TODO test with real creds
public static void main(String[] args) {
String username = "[email protected]";
String password = "6.tw*gghr.fyDDjkjaZj";
String tokenServerUrl = AUTH_URL;

tokens = OAuth2Util.getTokensForUsernameAndPassword(username, password, Map.of("requestAdminToken", "true"), tokenServerUrl);
}
}

50 changes: 16 additions & 34 deletions src/main/java/com/impactupgrade/nucleus/client/SpokeClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,17 @@
import com.impactupgrade.nucleus.environment.EnvironmentConfig;
import com.impactupgrade.nucleus.model.CrmContact;
import com.impactupgrade.nucleus.util.HttpClient;
import com.impactupgrade.nucleus.util.OAuth2Util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import static com.impactupgrade.nucleus.util.HttpClient.TokenResponse;
import static com.impactupgrade.nucleus.util.HttpClient.get;
import static com.impactupgrade.nucleus.util.HttpClient.post;
import static com.impactupgrade.nucleus.util.HttpClient.put;
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;

// TODO: To eventually become a spoke-phone-java-client open source lib?
Expand All @@ -32,11 +29,15 @@ public class SpokeClient {

protected final Environment env;

protected String accessToken;
protected Calendar accessTokenExpiration;
protected static OAuth2Util.Tokens tokens;

private String clientId;
private String clientSecret;

public SpokeClient(Environment env) {
this.env = env;
this.clientId = env.getConfig().spoke.clientId;
this.clientSecret = env.getConfig().spoke.clientSecret;
}

public List<Phonebook> getPhonebooks() {
Expand Down Expand Up @@ -117,37 +118,15 @@ public static class ContactRequest {
}

protected HttpClient.HeaderBuilder headers() {
if (isAccessTokenInvalid()) {
log.info("Getting new access token...");
TokenResponse tokenResponse = getAccessToken();
accessToken = tokenResponse.accessToken;
Calendar onehour = Calendar.getInstance();
onehour.add(Calendar.SECOND, tokenResponse.expiresIn);
accessTokenExpiration = onehour;
tokens = OAuth2Util.refreshTokens(tokens, AUTH_ENDPOINT);
if (tokens == null) {
tokens = OAuth2Util.getTokensForClientCredentials(clientId, clientSecret, AUTH_ENDPOINT);
}
System.out.println(accessToken);
String accessToken = tokens != null ? tokens.accessToken() : null;
return HttpClient.HeaderBuilder.builder().authBearerToken(accessToken);
}

protected boolean isAccessTokenInvalid() {
Calendar now = Calendar.getInstance();
return Strings.isNullOrEmpty(accessToken) || now.after(accessTokenExpiration);
}

protected TokenResponse getAccessToken() {
// TODO: Map.of should be ablet o be used instead of Form (see VirtuousClient), but getting errors about no writer
return post(
AUTH_ENDPOINT,
new Form()
.param("client_id", env.getConfig().spoke.clientId)
.param("client_secret", env.getConfig().spoke.clientSecret)
.param("grant_type", "client_credentials"),
APPLICATION_FORM_URLENCODED,
HttpClient.HeaderBuilder.builder(),
TokenResponse.class
);
}

//TODO: remove once done with testing
public static void main(String[] args) {
Environment env = new Environment() {
@Override
Expand All @@ -168,6 +147,9 @@ public EnvironmentConfig getConfig() {
// Phonebook phonebook = spokeClient.createPhonebook("Salesforce US", "Salesforce contacts in the US", "US");
List<Phonebook> phonebooks = spokeClient.getPhonebooks();
// Contact contact = spokeClient.upsertContact(crmContact, "Salesforce", phonebooks.get(0).id);
System.out.println(phonebooks);

// To check same access token is used
phonebooks = spokeClient.getPhonebooks();
}

}
Loading

0 comments on commit 67298e8

Please sign in to comment.