diff options
Diffstat (limited to 'src/com/p4square')
-rw-r--r-- | src/com/p4square/f1oauth/Attribute.java | 87 | ||||
-rw-r--r-- | src/com/p4square/f1oauth/F1API.java | 44 | ||||
-rw-r--r-- | src/com/p4square/f1oauth/F1Access.java | 242 | ||||
-rw-r--r-- | src/com/p4square/f1oauth/F1Exception.java | 15 | ||||
-rw-r--r-- | src/com/p4square/f1oauth/SecondPartyVerifier.java | 23 | ||||
-rw-r--r-- | src/com/p4square/grow/GrowProcessComponent.java | 1 | ||||
-rw-r--r-- | src/com/p4square/grow/frontend/AssessmentResultsPage.java | 25 | ||||
-rw-r--r-- | src/com/p4square/grow/tools/AttributeTool.java | 143 |
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; + } +} |