summaryrefslogtreecommitdiff
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/p4square/f1oauth/Attribute.java87
-rw-r--r--src/com/p4square/f1oauth/F1API.java44
-rw-r--r--src/com/p4square/f1oauth/F1Access.java242
-rw-r--r--src/com/p4square/f1oauth/F1Exception.java15
-rw-r--r--src/com/p4square/f1oauth/SecondPartyVerifier.java23
-rw-r--r--src/com/p4square/grow/GrowProcessComponent.java1
-rw-r--r--src/com/p4square/grow/frontend/AssessmentResultsPage.java25
-rw-r--r--src/com/p4square/grow/tools/AttributeTool.java143
8 files changed, 511 insertions, 69 deletions
diff --git a/src/com/p4square/f1oauth/Attribute.java b/src/com/p4square/f1oauth/Attribute.java
new file mode 100644
index 0000000..fa46d90
--- /dev/null
+++ b/src/com/p4square/f1oauth/Attribute.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.f1oauth;
+
+import java.util.Date;
+
+/**
+ * F1 Attribute Data.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class Attribute {
+ /*Attribute
+ *{
+ "attribute": {
+ "@id": "",
+ "@uri": "",
+ "person": {
+ "@id": "1636208",
+ "@uri": "https://demo.fellowshiponeapi.com/v1/People/1636208"
+ },
+ "attributeGroup": {
+ "@id": "",
+ "@uri": "",
+ "name": null,
+ "attribute": {
+ "@id": "958",
+ "@uri": "",
+ "name": null
+ }
+ },
+ "startDate": null,
+ "endDate": null,
+ "comment": null,
+ "createdDate": null,
+ "lastUpdatedDate": null
+ }
+ */
+
+ private Date mStartDate;
+ private Date mEndDate;
+ private String mComment;
+
+ /**
+ * @return the start date for the attribute.
+ */
+ public Date getStartDate() {
+ return mStartDate;
+ }
+
+ /**
+ * Set the start date for the attribute.
+ */
+ public void setStartDate(Date date) {
+ mStartDate = date;
+ }
+
+ /**
+ * @return the end date for the attribute.
+ */
+ public Date getEndDate() {
+ return mEndDate;
+ }
+
+ /**
+ * Set the end date for the attribute.
+ */
+ public void setEndDate(Date date) {
+ mEndDate = date;
+ }
+
+ /**
+ * @return The comment on the Attribute.
+ */
+ public String getComment() {
+ return mComment;
+ }
+
+ /**
+ * Set the comment on the attribute.
+ */
+ public void setComment(String comment) {
+ mComment = comment;
+ }
+}
diff --git a/src/com/p4square/f1oauth/F1API.java b/src/com/p4square/f1oauth/F1API.java
new file mode 100644
index 0000000..88801db
--- /dev/null
+++ b/src/com/p4square/f1oauth/F1API.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.f1oauth;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.p4square.restlet.oauth.OAuthException;
+import com.p4square.restlet.oauth.OAuthUser;
+
+/**
+ * F1 API methods which require an authenticated user.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public interface F1API {
+ /**
+ * Fetch information about a user.
+ *
+ * @param user The user to fetch information about.
+ * @return An F1User object.
+ */
+ F1User getF1User(OAuthUser user) throws OAuthException, IOException;
+
+ /**
+ * Fetch a list of all attributes ids and names.
+ *
+ * @return A Map of attribute name to attribute id.
+ */
+ Map<String, String> getAttributeList() throws F1Exception;
+
+ /**
+ * Add an attribute to the user.
+ *
+ * @param user The user to add the attribute to.
+ * @param attributeName The attribute to add.
+ * @param attribute The attribute to add.
+ */
+ boolean addAttribute(String userId, String attributeName, Attribute attribute)
+ throws F1Exception;
+
+}
diff --git a/src/com/p4square/f1oauth/F1Access.java b/src/com/p4square/f1oauth/F1Access.java
index 35957bf..32550c4 100644
--- a/src/com/p4square/f1oauth/F1Access.java
+++ b/src/com/p4square/f1oauth/F1Access.java
@@ -4,19 +4,26 @@
package com.p4square.f1oauth;
+import java.io.IOException;
import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import org.apache.log4j.Logger;
import org.restlet.Context;
-import org.restlet.Response;
import org.restlet.Request;
+import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Status;
import org.restlet.engine.util.Base64;
+import org.restlet.ext.jackson.JacksonRepresentation;
+import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import com.p4square.restlet.oauth.OAuthException;
@@ -42,11 +49,16 @@ public class F1Access {
private static final String ACCESSTOKEN_URL= "Tokens/AccessToken";
private static final String TRUSTED_ACCESSTOKEN_URL = "/AccessToken";
+ private static final SimpleDateFormat DATE_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+
private final String mBaseUrl;
private final String mMethod;
private final OAuthHelper mOAuthHelper;
+ private final Map<String, String> mAttributeIdByName;
+
/**
*/
public F1Access(Context context, String consumerKey, String consumerSecret,
@@ -91,6 +103,7 @@ public class F1Access {
}
};
+ mAttributeIdByName = new HashMap<>();
}
/**
@@ -144,64 +157,205 @@ public class F1Access {
}
}
- /*
- public addAttribute(Attribute attribute, String comment) {
- String baseUrl = getBaseUrl();
- Map newAttributeTemplate = null;
-
- // Get Attribute Template
- Request request = new Request(Method.GET,
- baseUrl + "People/" + getIdentifier() + "/Attributes/new.json");
- request.setChallengeResponse(getChallengeResponse());
- Response response = getContext().getClientDispatcher().handle(request);
-
- Representation representation = response.getEntity();
- try {
- Status status = response.getStatus();
- if (status.isSuccess()) {
- JacksonRepresentation<Map> entity = new JacksonRepresentation<Map>(response.getEntity(), Map.class);
- newAttributeTemplate = entity.getObject();
- }
+ /**
+ * @return An F1API authenticated by the given user.
+ */
+ public F1API getAuthenticatedApi(OAuthUser user) {
+ return new AuthenticatedApi(user);
+ }
+
+ private class AuthenticatedApi implements F1API {
+ private final OAuthUser mUser;
+
+ public AuthenticatedApi(OAuthUser user) {
+ mUser = user;
+ }
- } finally {
- if (representation != null) {
- representation.release();
+ /**
+ * Fetch information about a user.
+ *
+ * @param user The user to fetch information about.
+ * @return An F1User object.
+ */
+ @Override
+ public F1User getF1User(OAuthUser user) throws OAuthException, IOException {
+ Request request = new Request(Method.GET, user.getLocation() + ".json");
+ request.setChallengeResponse(mUser.getChallengeResponse());
+ Response response = mOAuthHelper.getResponse(request);
+
+ try {
+ Status status = response.getStatus();
+ if (status.isSuccess()) {
+ JacksonRepresentation<Map> entity =
+ new JacksonRepresentation<Map>(response.getEntity(), Map.class);
+ Map data = entity.getObject();
+ return new F1User(user, data);
+
+ } else {
+ throw new OAuthException(status);
+ }
+ } finally {
+ if (response.getEntity() != null) {
+ response.release();
+ }
}
}
- if (newAttributeTemplate == null) {
- LOG.error("Could not retrieve attribute template!");
- return;
+ @Override
+ public Map<String, String> getAttributeList() throws F1Exception {
+ // Note: this list is shared by all F1 users.
+ synchronized (mAttributeIdByName) {
+ if (mAttributeIdByName.size() == 0) {
+ // Reload attributes. Maybe it will be there now...
+ Request request = new Request(Method.GET,
+ mBaseUrl + "People/AttributeGroups.json");
+ request.setChallengeResponse(mUser.getChallengeResponse());
+ Response response = mOAuthHelper.getResponse(request);
+
+ Representation representation = response.getEntity();
+ try {
+ Status status = response.getStatus();
+ if (status.isSuccess()) {
+ JacksonRepresentation<Map> entity =
+ new JacksonRepresentation<Map>(response.getEntity(), Map.class);
+
+ Map attributeGroups = (Map) entity.getObject().get("attributeGroups");
+ List<Map> groups = (List<Map>) attributeGroups.get("attributeGroup");
+
+ for (Map group : groups) {
+ List<Map> attributes = (List<Map>) group.get("attribute");
+ if (attributes != null) {
+ for (Map attribute : attributes) {
+ String id = (String) attribute.get("@id");
+ String name = ((String) attribute.get("name"));
+ mAttributeIdByName.put(name.toLowerCase(), id);
+ LOG.debug("Caching attribute '" + name
+ + "' with id '" + id + "'");
+ }
+ }
+ }
+ }
+
+ } catch (IOException e) {
+ throw new F1Exception("Could not parse AttributeGroups.", e);
+
+ } finally {
+ if (representation != null) {
+ representation.release();
+ }
+ }
+ }
+
+ return mAttributeIdByName;
+ }
}
- // Populate Attribute Template
+ /**
+ * Add an attribute to the user.
+ *
+ * @param user The user to add the attribute to.
+ * @param attributeName The attribute to add.
+ * @param attribute The attribute to add.
+ */
+ public boolean addAttribute(String userId, String attributeName, Attribute attribute)
+ throws F1Exception {
+
+ // Get the attribute id.
+ String attributeId = getAttributeId(attributeName);
+ if (attributeId == null) {
+ throw new F1Exception("Could not find id for " + attributeName);
+ }
+
+ // Get Attribute Template
+ Map attributeTemplate = null;
+
+ {
+ Request request = new Request(Method.GET,
+ mBaseUrl + "People/" + userId + "/Attributes/new.json");
+ request.setChallengeResponse(mUser.getChallengeResponse());
+ Response response = mOAuthHelper.getResponse(request);
+
+ Representation representation = response.getEntity();
+ try {
+ Status status = response.getStatus();
+ if (status.isSuccess()) {
+ JacksonRepresentation<Map> entity =
+ new JacksonRepresentation<Map>(response.getEntity(), Map.class);
+ attributeTemplate = entity.getObject();
+
+ } else {
+ throw new F1Exception("Failed to retrieve attribute template: "
+ + status);
+ }
+
+ } catch (IOException e) {
+ throw new F1Exception("Could not parse attribute template.", e);
+
+ } finally {
+ if (representation != null) {
+ representation.release();
+ }
+ }
+ }
+
+ if (attributeTemplate == null) {
+ throw new F1Exception("Could not retrieve attribute template.");
+ }
+
+ // Populate Attribute Template
+ Map attributeMap = (Map) attributeTemplate.get("attribute");
+ Map attributeGroup = (Map) attributeMap.get("attributeGroup");
+ Map<String, String> attributeIdMap = new HashMap<>();
+ attributeIdMap.put("@id", attributeId);
+ attributeGroup.put("attribute", attributeIdMap);
- // POST new attribute
- Request request = new Request(Method.POST,
- baseUrl + "People/" + getIdentifier() + "/Attributes.json");
- request.setChallengeResponse(getChallengeResponse());
- Response response = getContext().getClientDispatcher().handle(request);
+ if (attribute.getStartDate() != null) {
+ attributeMap.put("startDate", DATE_FORMAT.format(attribute.getStartDate()));
+ }
- Representation representation = response.getEntity();
- try {
- Status status = response.getStatus();
- if (status.isSuccess()) {
- JacksonRepresentation<Map> entity = new JacksonRepresentation<Map>(response.getEntity(), Map.class);
- newAttributeTemplate = entity.getObject();
+ if (attribute.getStartDate() != null) {
+ attributeMap.put("endDate", DATE_FORMAT.format(attribute.getStartDate()));
}
- } finally {
- if (representation != null) {
- representation.release();
+ attributeMap.put("comment", attribute.getComment());
+
+ // POST new attribute
+ Status status;
+ {
+ Request request = new Request(Method.POST,
+ mBaseUrl + "People/" + userId + "/Attributes.json");
+ request.setChallengeResponse(mUser.getChallengeResponse());
+ request.setEntity(new JacksonRepresentation<Map>(attributeTemplate));
+ Response response = mOAuthHelper.getResponse(request);
+
+ Representation representation = response.getEntity();
+ try {
+ status = response.getStatus();
+
+ if (status.isSuccess()) {
+ return true;
+ }
+
+ } finally {
+ if (representation != null) {
+ representation.release();
+ }
+ }
}
+
+ LOG.debug("addAttribute failed POST: " + status);
+ return false;
}
- if (newAttributeTemplate == null) {
- LOG.error("Could retrieve attribute template!");
- return;
+ /**
+ * @return an attribute id for the given attribute name.
+ */
+ private String getAttributeId(String attributeName) throws F1Exception {
+ Map<String, String> attributeMap = getAttributeList();
+
+ return attributeMap.get(attributeName.toLowerCase());
}
}
- */
}
diff --git a/src/com/p4square/f1oauth/F1Exception.java b/src/com/p4square/f1oauth/F1Exception.java
new file mode 100644
index 0000000..54c1a77
--- /dev/null
+++ b/src/com/p4square/f1oauth/F1Exception.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.f1oauth;
+
+public class F1Exception extends Exception {
+ public F1Exception(String message) {
+ super(message);
+ }
+
+ public F1Exception(String message, Exception cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/com/p4square/f1oauth/SecondPartyVerifier.java b/src/com/p4square/f1oauth/SecondPartyVerifier.java
index e2d6d00..882c7e7 100644
--- a/src/com/p4square/f1oauth/SecondPartyVerifier.java
+++ b/src/com/p4square/f1oauth/SecondPartyVerifier.java
@@ -54,7 +54,7 @@ public class SecondPartyVerifier implements Verifier {
OAuthUser ouser = mHelper.getAccessToken(username, password);
// Once we have a user, fetch the people record to get the user id.
- F1User user = getF1User(ouser);
+ F1User user = mHelper.getAuthenticatedApi(ouser).getF1User(ouser);
user.setEmail(username);
// This seems like a hack... but it'll work
@@ -69,25 +69,4 @@ public class SecondPartyVerifier implements Verifier {
return RESULT_INVALID; // Invalid credentials
}
- private F1User getF1User(OAuthUser user) throws OAuthException, IOException {
- Request request = new Request(Method.GET, user.getLocation() + ".json");
- request.setChallengeResponse(user.getChallengeResponse());
- Response response = mDispatcher.handle(request);
-
- try {
- Status status = response.getStatus();
- if (status.isSuccess()) {
- JacksonRepresentation<Map> entity = new JacksonRepresentation<Map>(response.getEntity(), Map.class);
- Map data = entity.getObject();
- return new F1User(user, data);
-
- } else {
- throw new OAuthException(status);
- }
- } finally {
- if (response.getEntity() != null) {
- response.release();
- }
- }
- }
}
diff --git a/src/com/p4square/grow/GrowProcessComponent.java b/src/com/p4square/grow/GrowProcessComponent.java
index 18b3d5b..791f177 100644
--- a/src/com/p4square/grow/GrowProcessComponent.java
+++ b/src/com/p4square/grow/GrowProcessComponent.java
@@ -10,7 +10,6 @@ import java.io.IOException;
import org.apache.log4j.Logger;
import org.restlet.Application;
-import org.restlet.Client;
import org.restlet.Component;
import org.restlet.Restlet;
import org.restlet.data.ChallengeScheme;
diff --git a/src/com/p4square/grow/frontend/AssessmentResultsPage.java b/src/com/p4square/grow/frontend/AssessmentResultsPage.java
index c205503..ff1832c 100644
--- a/src/com/p4square/grow/frontend/AssessmentResultsPage.java
+++ b/src/com/p4square/grow/frontend/AssessmentResultsPage.java
@@ -4,6 +4,7 @@
package com.p4square.grow.frontend;
+import java.util.Date;
import java.util.Map;
import freemarker.template.Template;
@@ -22,9 +23,12 @@ import com.p4square.fmfacade.json.JsonRequestClient;
import com.p4square.fmfacade.json.JsonResponse;
import com.p4square.fmfacade.json.ClientException;
+import com.p4square.f1oauth.Attribute;
+import com.p4square.f1oauth.F1API;
import com.p4square.f1oauth.F1User;
import com.p4square.grow.config.Config;
+import com.p4square.grow.provider.JsonEncodedProvider;
/**
* This page fetches the user's final score and displays the transitional page between
@@ -105,7 +109,23 @@ public class AssessmentResultsPage extends FreeMarkerPageResource {
F1User user = (F1User) getRequest().getClientInfo().getUser();
- // TODO: Update the attribute.
+ // Update the attribute.
+ String attributeName = "Assessment Complete - " + results.get("result");
+
+ try {
+ Attribute attribute = new Attribute();
+ attribute.setStartDate(new Date());
+ attribute.setComment(JsonEncodedProvider.MAPPER.writeValueAsString(results));
+
+ F1API f1 = mGrowFrontend.getF1Access().getAuthenticatedApi(user);
+ if (!f1.addAttribute(user.getIdentifier(), attributeName, attribute)) {
+ LOG.error("addAttribute failed for " + user.getIdentifier()
+ + " with attribute " + attributeName);
+ }
+ } catch (Exception e) {
+ LOG.error("addAttribute failed for " + user.getIdentifier()
+ + " with attribute " + attributeName, e);
+ }
}
/**
@@ -124,7 +144,8 @@ public class AssessmentResultsPage extends FreeMarkerPageResource {
final JsonResponse response = mJsonClient.get(getBackendEndpoint() + uri);
final Status status = response.getStatus();
if (!status.isSuccess() && !Status.CLIENT_ERROR_NOT_FOUND.equals(status)) {
- LOG.warn("Error making backend request for '" + uri + "'. status = " + response.getStatus().toString());
+ LOG.warn("Error making backend request for '" + uri + "'. status = "
+ + response.getStatus().toString());
}
return response;
diff --git a/src/com/p4square/grow/tools/AttributeTool.java b/src/com/p4square/grow/tools/AttributeTool.java
new file mode 100644
index 0000000..0775087
--- /dev/null
+++ b/src/com/p4square/grow/tools/AttributeTool.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.grow.tools;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+
+import org.restlet.Client;
+import org.restlet.Context;
+import org.restlet.data.Protocol;
+
+import com.p4square.grow.config.Config;
+import com.p4square.f1oauth.Attribute;
+import com.p4square.f1oauth.F1Access;
+import com.p4square.f1oauth.F1API;
+import com.p4square.f1oauth.F1Exception;
+import com.p4square.restlet.oauth.OAuthUser;
+
+/**
+ * Tool for manipulating F1 Attributes.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class AttributeTool {
+
+ private static Config mConfig;
+ private static F1API mF1API;
+
+ public static void usage() {
+ System.out.println("java com.p4square.grow.tools.AttributeTool <command>...\n");
+ System.out.println("Commands:");
+ System.out.println("\t--domain <domain> Set config domain");
+ System.out.println("\t--dev Set config domain to dev");
+ System.out.println("\t--config <file> Merge in config file");
+ System.out.println("\t--list List all attributes");
+ System.out.println("\t--assign <user> <attribute> <comment> Assign an attribute");
+ }
+
+ public static void main(String... args) {
+ if (args.length == 0) {
+ usage();
+ System.exit(1);
+ }
+
+ mConfig = new Config();
+
+ try {
+ mConfig.updateConfig(AttributeTool.class.getResourceAsStream("/grow.properties"));
+
+ int offset = 0;
+ while (offset < args.length) {
+ if ("--domain".equals(args[offset])) {
+ mConfig.setDomain(args[offset + 1]);
+ mF1API = null;
+ offset += 2;
+
+ } else if ("--dev".equals(args[offset])) {
+ mConfig.setDomain("dev");
+ mF1API = null;
+ offset += 1;
+
+ } else if ("--config".equals(args[offset])) {
+ mConfig.updateConfig(args[offset + 1]);
+ mF1API = null;
+ offset += 2;
+
+ } else if ("--list".equals(args[offset])) {
+ offset = list(args, ++offset);
+
+ } else if ("--assign".equals(args[offset])) {
+ offset = assign(args, ++offset);
+
+ } else {
+ throw new IllegalArgumentException("Unknown command " + args[offset]);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(2);
+ }
+ }
+
+ private static F1API getF1API() throws Exception {
+ if (mF1API == null) {
+ Context context = new Context();
+ Client client = new Client(context, Arrays.asList(Protocol.HTTP, Protocol.HTTPS));
+ context.setClientDispatcher(client);
+
+ F1Access f1Access = new F1Access(context,
+ mConfig.getString("f1ConsumerKey"),
+ mConfig.getString("f1ConsumerSecret"),
+ mConfig.getString("f1BaseUrl"),
+ mConfig.getString("f1ChurchCode"),
+ F1Access.UserType.WEBLINK);
+
+ // Gather Username and Password
+ String username = System.console().readLine("F1 Username: ");
+ char[] password = System.console().readPassword("F1 Password: ");
+
+ OAuthUser user = f1Access.getAccessToken(username, new String(password));
+ Arrays.fill(password, ' '); // Lost cause, but I'll still try.
+
+ mF1API = f1Access.getAuthenticatedApi(user);
+ }
+
+ return mF1API;
+ }
+
+ private static int list(String[] args, int offset) throws Exception {
+ final F1API f1 = getF1API();
+
+ final Map<String, String> attributes = f1.getAttributeList();
+ System.out.printf("%7s %s\n", "ID", "Name");
+ for (Map.Entry<String, String> entry : attributes.entrySet()) {
+ System.out.printf("%7s %s\n", entry.getValue(), entry.getKey());
+ }
+
+ return offset;
+ }
+
+ private static int assign(String[] args, int offset) throws Exception {
+ final String userId = args[offset++];
+ final String attributeName = args[offset++];
+ final String comment = args[offset++];
+
+ final F1API f1 = getF1API();
+
+ Attribute attribute = new Attribute();
+ attribute.setStartDate(new Date());
+ attribute.setComment(comment);
+
+ if (f1.addAttribute(userId, attributeName, attribute)) {
+ System.out.println("Added attribute " + attributeName + " for " + userId);
+ } else {
+ System.out.println("Failed to add attribute " + attributeName + " for " + userId);
+ }
+
+ return offset;
+ }
+}