summaryrefslogtreecommitdiff
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/p4square/f1oauth/Attribute.java90
-rw-r--r--src/com/p4square/f1oauth/F1API.java56
-rw-r--r--src/com/p4square/f1oauth/F1Access.java594
-rw-r--r--src/com/p4square/f1oauth/F1Exception.java15
-rw-r--r--src/com/p4square/f1oauth/F1ProgressReporter.java57
-rw-r--r--src/com/p4square/f1oauth/F1User.java70
-rw-r--r--src/com/p4square/f1oauth/FellowshipOneIntegrationDriver.java55
-rw-r--r--src/com/p4square/f1oauth/SecondPartyAuthenticator.java52
-rw-r--r--src/com/p4square/f1oauth/SecondPartyVerifier.java72
-rw-r--r--src/com/p4square/fmfacade/FMFacade.java107
-rw-r--r--src/com/p4square/fmfacade/FreeMarkerPageResource.java98
-rw-r--r--src/com/p4square/fmfacade/ftl/GetMethod.java94
-rw-r--r--src/com/p4square/fmfacade/json/ClientException.java20
-rw-r--r--src/com/p4square/fmfacade/json/JsonRequestClient.java109
-rw-r--r--src/com/p4square/fmfacade/json/JsonResponse.java87
-rw-r--r--src/com/p4square/grow/GrowProcessComponent.java166
-rw-r--r--src/com/p4square/grow/backend/BackendVerifier.java92
-rw-r--r--src/com/p4square/grow/backend/CassandraGrowData.java172
-rw-r--r--src/com/p4square/grow/backend/DynamoGrowData.java180
-rw-r--r--src/com/p4square/grow/backend/GrowBackend.java211
-rw-r--r--src/com/p4square/grow/backend/GrowData.java36
-rw-r--r--src/com/p4square/grow/backend/apiinfo.html41
-rw-r--r--src/com/p4square/grow/backend/db/CassandraCollectionProvider.java109
-rw-r--r--src/com/p4square/grow/backend/db/CassandraDatabase.java212
-rw-r--r--src/com/p4square/grow/backend/db/CassandraKey.java34
-rw-r--r--src/com/p4square/grow/backend/db/CassandraProviderImpl.java37
-rw-r--r--src/com/p4square/grow/backend/db/CassandraTrainingRecordProvider.java71
-rw-r--r--src/com/p4square/grow/backend/dynamo/DbTool.java481
-rw-r--r--src/com/p4square/grow/backend/dynamo/DynamoCollectionProviderImpl.java109
-rw-r--r--src/com/p4square/grow/backend/dynamo/DynamoDatabase.java307
-rw-r--r--src/com/p4square/grow/backend/dynamo/DynamoKey.java56
-rw-r--r--src/com/p4square/grow/backend/dynamo/DynamoProviderImpl.java37
-rw-r--r--src/com/p4square/grow/backend/feed/FeedDataProvider.java33
-rw-r--r--src/com/p4square/grow/backend/feed/ThreadResource.java106
-rw-r--r--src/com/p4square/grow/backend/feed/TopicResource.java117
-rw-r--r--src/com/p4square/grow/backend/resources/AccountResource.java87
-rw-r--r--src/com/p4square/grow/backend/resources/BannerResource.java85
-rw-r--r--src/com/p4square/grow/backend/resources/SurveyResource.java115
-rw-r--r--src/com/p4square/grow/backend/resources/SurveyResultsResource.java253
-rw-r--r--src/com/p4square/grow/backend/resources/TrainingRecordResource.java235
-rw-r--r--src/com/p4square/grow/backend/resources/TrainingResource.java97
-rw-r--r--src/com/p4square/grow/ccb/CCBProgressReporter.java104
-rw-r--r--src/com/p4square/grow/ccb/CCBUser.java37
-rw-r--r--src/com/p4square/grow/ccb/CCBUserVerifier.java50
-rw-r--r--src/com/p4square/grow/ccb/ChurchCommunityBuilderIntegrationDriver.java61
-rw-r--r--src/com/p4square/grow/ccb/CustomFieldCache.java126
-rw-r--r--src/com/p4square/grow/ccb/MonitoredCCBAPI.java96
-rw-r--r--src/com/p4square/grow/config/Config.java203
-rw-r--r--src/com/p4square/grow/frontend/AccountRedirectResource.java113
-rw-r--r--src/com/p4square/grow/frontend/AssessmentResetPage.java99
-rw-r--r--src/com/p4square/grow/frontend/AssessmentResultsPage.java145
-rw-r--r--src/com/p4square/grow/frontend/AuthenticatedResource.java18
-rw-r--r--src/com/p4square/grow/frontend/ChapterCompletePage.java209
-rw-r--r--src/com/p4square/grow/frontend/ErrorPage.java77
-rw-r--r--src/com/p4square/grow/frontend/FeedData.java105
-rw-r--r--src/com/p4square/grow/frontend/FeedResource.java101
-rw-r--r--src/com/p4square/grow/frontend/GroupLeaderTrainingPageResource.java26
-rw-r--r--src/com/p4square/grow/frontend/GrowFrontend.java230
-rw-r--r--src/com/p4square/grow/frontend/IntegrationDriver.java26
-rw-r--r--src/com/p4square/grow/frontend/JsonRequestProvider.java96
-rw-r--r--src/com/p4square/grow/frontend/LoginFormAuthenticator.java146
-rw-r--r--src/com/p4square/grow/frontend/LoginPageResource.java77
-rw-r--r--src/com/p4square/grow/frontend/LogoutResource.java40
-rw-r--r--src/com/p4square/grow/frontend/NewAccountResource.java135
-rw-r--r--src/com/p4square/grow/frontend/NewBelieverResource.java72
-rw-r--r--src/com/p4square/grow/frontend/NotFoundException.java13
-rw-r--r--src/com/p4square/grow/frontend/ProgressReporter.java30
-rw-r--r--src/com/p4square/grow/frontend/SurveyPageResource.java343
-rw-r--r--src/com/p4square/grow/frontend/TrainingPageResource.java268
-rw-r--r--src/com/p4square/grow/frontend/VideosResource.java133
-rw-r--r--src/com/p4square/grow/model/Answer.java142
-rw-r--r--src/com/p4square/grow/model/Banner.java20
-rw-r--r--src/com/p4square/grow/model/Chapter.java112
-rw-r--r--src/com/p4square/grow/model/CircleQuestion.java89
-rw-r--r--src/com/p4square/grow/model/ImageQuestion.java24
-rw-r--r--src/com/p4square/grow/model/Message.java103
-rw-r--r--src/com/p4square/grow/model/MessageThread.java60
-rw-r--r--src/com/p4square/grow/model/Playlist.java192
-rw-r--r--src/com/p4square/grow/model/Point.java79
-rw-r--r--src/com/p4square/grow/model/QuadQuestion.java89
-rw-r--r--src/com/p4square/grow/model/QuadScoringEngine.java49
-rw-r--r--src/com/p4square/grow/model/Question.java165
-rw-r--r--src/com/p4square/grow/model/RecordedAnswer.java34
-rw-r--r--src/com/p4square/grow/model/Score.java119
-rw-r--r--src/com/p4square/grow/model/ScoringEngine.java26
-rw-r--r--src/com/p4square/grow/model/SimpleScoringEngine.java26
-rw-r--r--src/com/p4square/grow/model/SliderQuestion.java24
-rw-r--r--src/com/p4square/grow/model/SliderScoringEngine.java35
-rw-r--r--src/com/p4square/grow/model/TextQuestion.java24
-rw-r--r--src/com/p4square/grow/model/TrainingRecord.java49
-rw-r--r--src/com/p4square/grow/model/UserRecord.java183
-rw-r--r--src/com/p4square/grow/model/VideoRecord.java85
-rw-r--r--src/com/p4square/grow/provider/CollectionProvider.java59
-rw-r--r--src/com/p4square/grow/provider/DelegateCollectionProvider.java69
-rw-r--r--src/com/p4square/grow/provider/DelegateProvider.java40
-rw-r--r--src/com/p4square/grow/provider/JsonEncodedProvider.java83
-rw-r--r--src/com/p4square/grow/provider/MapCollectionProvider.java74
-rw-r--r--src/com/p4square/grow/provider/MapProvider.java28
-rw-r--r--src/com/p4square/grow/provider/Provider.java31
-rw-r--r--src/com/p4square/grow/provider/ProvidesAssessments.java20
-rw-r--r--src/com/p4square/grow/provider/ProvidesQuestions.java19
-rw-r--r--src/com/p4square/grow/provider/ProvidesStrings.java19
-rw-r--r--src/com/p4square/grow/provider/ProvidesTrainingRecords.java27
-rw-r--r--src/com/p4square/grow/provider/ProvidesUserRecords.java19
-rw-r--r--src/com/p4square/grow/provider/ProvidesVideos.java16
-rw-r--r--src/com/p4square/grow/provider/TrainingRecordProvider.java41
-rw-r--r--src/com/p4square/grow/tools/AssessmentStats.java218
-rw-r--r--src/com/p4square/grow/tools/AttributeBackfillTool.java268
-rw-r--r--src/com/p4square/grow/tools/AttributeTool.java184
-rw-r--r--src/com/p4square/restlet/metrics/MetricRouter.java61
-rw-r--r--src/com/p4square/restlet/metrics/MetricsApplication.java43
-rw-r--r--src/com/p4square/restlet/metrics/MetricsResource.java32
-rw-r--r--src/com/p4square/restlet/oauth/OAuthAuthenticator.java95
-rw-r--r--src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java177
-rw-r--r--src/com/p4square/restlet/oauth/OAuthException.java25
-rw-r--r--src/com/p4square/restlet/oauth/OAuthHelper.java149
-rw-r--r--src/com/p4square/restlet/oauth/OAuthUser.java50
-rw-r--r--src/com/p4square/restlet/oauth/Token.java52
-rw-r--r--src/com/p4square/session/Session.java59
-rw-r--r--src/com/p4square/session/SessionAuthenticator.java36
-rw-r--r--src/com/p4square/session/SessionCheckingAuthenticator.java39
-rw-r--r--src/com/p4square/session/SessionCookieAuthenticator.java59
-rw-r--r--src/com/p4square/session/SessionCreatingAuthenticator.java46
-rw-r--r--src/com/p4square/session/Sessions.java155
124 files changed, 0 insertions, 12256 deletions
diff --git a/src/com/p4square/f1oauth/Attribute.java b/src/com/p4square/f1oauth/Attribute.java
deleted file mode 100644
index 64f2507..0000000
--- a/src/com/p4square/f1oauth/Attribute.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.f1oauth;
-
-import java.util.Date;
-
-/**
- * F1 Attribute Data.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Attribute {
- private final String mAttributeName;
- private String mId;
- private Date mStartDate;
- private Date mEndDate;
- private String mComment;
-
- /**
- * @param name The attribute name.
- */
- public Attribute(final String name) {
- mAttributeName = name;
- }
-
- /**
- * @return the Attribute name.
- */
- public String getAttributeName() {
- return mAttributeName;
- }
-
- /**
- * @return the id of this specific attribute instance.
- */
- public String getId() {
- return mId;
- }
-
- /**
- * Set the attribute id to id.
- */
- public void setId(final String id) {
- mId = id;
- }
-
- /**
- * @return the start date for the attribute.
- */
- public Date getStartDate() {
- return mStartDate;
- }
-
- /**
- * Set the start date for the attribute.
- */
- public void setStartDate(final 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(final Date date) {
- mEndDate = date;
- }
-
- /**
- * @return The comment on the Attribute.
- */
- public String getComment() {
- return mComment;
- }
-
- /**
- * Set the comment on the attribute.
- */
- public void setComment(final String comment) {
- mComment = comment;
- }
-}
diff --git a/src/com/p4square/f1oauth/F1API.java b/src/com/p4square/f1oauth/F1API.java
deleted file mode 100644
index a525c3f..0000000
--- a/src/com/p4square/f1oauth/F1API.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.f1oauth;
-
-import java.io.IOException;
-import java.util.List;
-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, Attribute attribute) throws F1Exception;
-
- /**
- * Return attributes assigned to user.
- *
- * A user may be assigned multiple attributes with the same name, thus even if
- * attributeName is specified, multiple attributes may be returned.
- *
- * @param userId The user to query.
- * @param attributeName A specific attribute to return, null for all.
- * @return A list of Attributes
- */
- List<Attribute> getAttribute(String userId, String attributeName) throws F1Exception;
-
-}
diff --git a/src/com/p4square/f1oauth/F1Access.java b/src/com/p4square/f1oauth/F1Access.java
deleted file mode 100644
index c3307f1..0000000
--- a/src/com/p4square/f1oauth/F1Access.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.f1oauth;
-
-import java.io.IOException;
-import java.net.URLEncoder;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.codahale.metrics.Counter;
-import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.Timer;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Context;
-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;
-import com.p4square.restlet.oauth.OAuthHelper;
-import com.p4square.restlet.oauth.OAuthUser;
-import com.p4square.restlet.oauth.Token;
-
-/**
- * F1 API Access.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class F1Access {
- public enum UserType {
- WEBLINK, PORTAL;
- }
-
- private static final Logger LOG = Logger.getLogger(F1Access.class);
-
- private static final String VERSION_STRING = "/v1/";
- private static final String REQUESTTOKEN_URL = "Tokens/RequestToken";
- private static final String AUTHORIZATION_URL = "Login";
- 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;
-
- private MetricRegistry mMetricRegistry;
-
- /**
- */
- public F1Access(Context context, String consumerKey, String consumerSecret,
- String baseUrl, String churchCode, UserType userType) {
-
- switch (userType) {
- case WEBLINK:
- mMethod = "WeblinkUser";
- break;
- case PORTAL:
- mMethod = "PortalUser";
- break;
- default:
- throw new IllegalArgumentException("Unknown UserType");
- }
-
- mBaseUrl = "https://" + churchCode + "." + baseUrl + VERSION_STRING;
-
- // Create the OAuthHelper. This implicitly registers the helper to
- // handle outgoing requests which need OAuth authentication.
- mOAuthHelper = new OAuthHelper(context, consumerKey, consumerSecret) {
- @Override
- protected String getRequestTokenUrl() {
- return mBaseUrl + REQUESTTOKEN_URL;
- }
-
- @Override
- public String getLoginUrl(Token requestToken, String callback) {
- String loginUrl = mBaseUrl + mMethod + AUTHORIZATION_URL
- + "?oauth_token=" + URLEncoder.encode(requestToken.getToken());
-
- if (callback != null) {
- loginUrl += "&oauth_callback=" + URLEncoder.encode(callback);
- }
-
- return loginUrl;
- }
-
- @Override
- protected String getAccessTokenUrl() {
- return mBaseUrl + ACCESSTOKEN_URL;
- }
- };
-
- mAttributeIdByName = new HashMap<>();
- }
-
- /**
- * Set the MetricRegistry to get metrics recorded.
- */
- public void setMetricRegistry(MetricRegistry metrics) {
- mMetricRegistry = metrics;
- }
-
- /**
- * Request an AccessToken for a particular username and password.
- *
- * This is an F1 extension to OAuth:
- * http://developer.fellowshipone.com/docs/v1/Util/AuthDocs.help#2creds
- */
- public OAuthUser getAccessToken(String username, String password) throws OAuthException {
- Timer.Context timer = getTimer("F1Access.getAccessToken.time");
- boolean success = true;
-
- try {
- Request request = new Request(Method.POST,
- mBaseUrl + mMethod + TRUSTED_ACCESSTOKEN_URL);
- request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_OAUTH));
-
- String base64String = Base64.encode((username + " " + password).getBytes(), false);
- request.setEntity(new StringRepresentation(base64String));
-
- return mOAuthHelper.processAccessTokenRequest(request);
-
- } catch (Exception e) {
- success = false;
- throw e;
-
- } finally {
- if (timer != null) {
- timer.stop();
- }
- if (success) {
- incrementCounter("F1Access.getAccessToken.success");
- } else {
- incrementCounter("F1Access.getAccessToken.failure");
- }
- }
- }
-
- /**
- * Create a new Account.
- *
- * @param firstname The user's first name.
- * @param lastname The user's last name.
- * @param email The user's email address.
- * @param redirect The URL to send the user to after confirming his address.
- *
- * @return true if created, false if the account already exists.
- */
- public boolean createAccount(String firstname, String lastname, String email, String redirect)
- throws OAuthException {
- Timer.Context timer = getTimer("F1Access.createAccount.time");
- boolean success = true;
-
- try {
- String req = String.format("{\n\"account\":{\n\"firstName\":\"%s\",\n"
- + "\"lastName\":\"%s\",\n\"email\":\"%s\",\n"
- + "\"urlRedirect\":\"%s\"\n}\n}",
- firstname, lastname, email, redirect);
-
- Request request = new Request(Method.POST, mBaseUrl + "Accounts");
- request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_OAUTH));
- request.setEntity(new StringRepresentation(req, MediaType.APPLICATION_JSON));
-
- Response response = mOAuthHelper.getResponse(request);
-
- Status status = response.getStatus();
- if (Status.SUCCESS_NO_CONTENT.equals(status)) {
- return true;
-
- } else if (Status.CLIENT_ERROR_CONFLICT.equals(status)) {
- return false;
-
- } else {
- throw new OAuthException(status);
- }
-
- } catch (Exception e) {
- success = false;
- throw e;
-
- } finally {
- if (timer != null) {
- timer.stop();
- }
- if (success) {
- incrementCounter("F1Access.createAccount.success");
- } else {
- incrementCounter("F1Access.createAccount.failure");
- }
- }
- }
-
- /**
- * @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;
- }
-
- /**
- * 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 {
- Timer.Context timer = getTimer("F1Access.getF1User.time");
- boolean success = true;
-
- try {
- 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();
- }
- }
-
- } catch (Exception e) {
- success = false;
- throw e;
-
- } finally {
- if (timer != null) {
- timer.stop();
- }
- if (success) {
- incrementCounter("F1Access.getF1User.success");
- } else {
- incrementCounter("F1Access.getF1User.failure");
- }
- }
- }
-
- @Override
- public Map<String, String> getAttributeList() throws F1Exception {
- // Note: this list is shared by all F1 users.
- synchronized (mAttributeIdByName) {
- if (mAttributeIdByName.size() == 0) {
- Timer.Context timer = getTimer("F1Access.getAttributeList.time");
- boolean success = true;
-
- try {
- // 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();
- }
- }
-
- } catch (Exception e) {
- success = false;
- throw e;
-
- } finally {
- if (timer != null) {
- timer.stop();
- }
- if (success) {
- incrementCounter("F1Access.getAttributeList.success");
- } else {
- incrementCounter("F1Access.getAttributeList.failure");
- }
- }
- }
-
- return mAttributeIdByName;
- }
- }
-
- /**
- * 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, Attribute attribute)
- throws F1Exception {
-
- // Get the attribute id.
- String attributeId = getAttributeId(attribute.getAttributeName());
- if (attributeId == null) {
- throw new F1Exception("Could not find id for " + attribute.getAttributeName());
- }
-
- // Get Attribute Template
- Map attributeTemplate = null;
-
- Timer.Context timer = getTimer("F1Access.addAttribute.GET.time");
- boolean success = true;
-
- try {
- 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();
- }
- }
- } catch (Exception e) {
- success = false;
- throw e;
-
- } finally {
- if (timer != null) {
- timer.stop();
- }
- if (success) {
- incrementCounter("F1Access.addAttribute.GET.success");
- } else {
- incrementCounter("F1Access.addAttribute.GET.failure");
- }
- }
-
- 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);
-
- if (attribute.getStartDate() != null) {
- attributeMap.put("startDate", DATE_FORMAT.format(attribute.getStartDate()));
- }
-
- if (attribute.getStartDate() != null) {
- attributeMap.put("endDate", DATE_FORMAT.format(attribute.getStartDate()));
- }
-
- attributeMap.put("comment", attribute.getComment());
-
- // POST new attribute
- Status status;
- timer = getTimer("F1Access.addAttribute.POST.time");
- success = true;
-
- try {
- 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();
- }
- }
- } catch (Exception e) {
- success = false;
- throw e;
-
- } finally {
- if (timer != null) {
- timer.stop();
- }
- if (success) {
- incrementCounter("F1Access.addAttribute.POST.success");
- } else {
- incrementCounter("F1Access.getAccessToken.POST.failure");
- }
- }
-
- LOG.debug("addAttribute failed POST: " + status);
- return false;
- }
-
- @Override
- public List<Attribute> getAttribute(String userId, String attributeNameFilter)
- throws F1Exception {
-
- Map attributesResponse;
-
- // Get Attributes
- Timer.Context timer = getTimer("F1Access.getAttribute.time");
- boolean success = true;
-
- try {
- Request request = new Request(Method.GET,
- mBaseUrl + "People/" + userId + "/Attributes.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);
- attributesResponse = entity.getObject();
-
- } else {
- throw new F1Exception("Failed to retrieve attributes: "
- + status);
- }
-
- } catch (IOException e) {
- throw new F1Exception("Could not parse attributes.", e);
-
- } finally {
- if (representation != null) {
- representation.release();
- }
- }
- } catch (Exception e) {
- success = false;
- throw e;
-
- } finally {
- if (timer != null) {
- timer.stop();
- }
- if (success) {
- incrementCounter("F1Access.getAttribute.success");
- } else {
- incrementCounter("F1Access.getAttribute.failure");
- }
- }
-
- // Parse Response
- List<Attribute> result = new ArrayList<>();
-
- try {
- // I feel like I'm writing lisp here...
- Map attributesMap = (Map) attributesResponse.get("attributes");
- if (attributesMap == null) {
- return result;
- }
-
- List<Map> attributes = (List<Map>) (attributesMap).get("attribute");
- for (Map attributeMap : attributes) {
- String id = (String) attributeMap.get("@id");
- String startDate = (String) attributeMap.get("startDate");
- String endDate = (String) attributeMap.get("endDate");
- String comment = (String) attributeMap.get("comment");
-
- Map attributeIdMap = (Map) ((Map) attributeMap.get("attributeGroup"))
- .get("attribute");
- String attributeName = (String) attributeIdMap.get("name");
-
- if (attributeNameFilter == null
- || attributeNameFilter.equalsIgnoreCase(attributeName)) {
-
- Attribute attribute = new Attribute(attributeName);
- attribute.setId(id);
- if (startDate != null) {
- attribute.setStartDate(DATE_FORMAT.parse(startDate));
- }
- if (endDate != null) {
- attribute.setEndDate(DATE_FORMAT.parse(endDate));
- }
- attribute.setComment(comment);
- result.add(attribute);
- }
- }
- } catch (Exception e) {
- throw new F1Exception("Failed to parse attributes response.", e);
- }
-
- return result;
- }
-
- /**
- * @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());
- }
-
- }
-
- private Timer.Context getTimer(String name) {
- if (mMetricRegistry != null) {
- return mMetricRegistry.timer(name).time();
- } else {
- return null;
- }
- }
-
- private void incrementCounter(String name) {
- if (mMetricRegistry != null) {
- mMetricRegistry.counter(name).inc();
- }
- }
-}
diff --git a/src/com/p4square/f1oauth/F1Exception.java b/src/com/p4square/f1oauth/F1Exception.java
deleted file mode 100644
index 54c1a77..0000000
--- a/src/com/p4square/f1oauth/F1Exception.java
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * 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/F1ProgressReporter.java b/src/com/p4square/f1oauth/F1ProgressReporter.java
deleted file mode 100644
index 8382020..0000000
--- a/src/com/p4square/f1oauth/F1ProgressReporter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.p4square.f1oauth;
-
-import com.p4square.grow.frontend.ProgressReporter;
-import org.apache.log4j.Logger;
-import org.restlet.security.User;
-
-import java.util.Date;
-
-/**
- * A ProgressReporter implementation to record progress in F1.
- */
-public class F1ProgressReporter implements ProgressReporter {
-
- private static final Logger LOG = Logger.getLogger(F1ProgressReporter.class);
-
- private F1Access mF1Access;
-
- public F1ProgressReporter(final F1Access f1access) {
- mF1Access = f1access;
- }
-
- @Override
- public void reportAssessmentComplete(final User user, final String level, final Date date, final String results) {
- String attributeName = "Assessment Complete - " + level;
- Attribute attribute = new Attribute(attributeName);
- attribute.setStartDate(date);
- attribute.setComment(results);
- addAttribute(user, attribute);
- }
-
- @Override
- public void reportChapterComplete(final User user, final String chapter, final Date date) {
- final String attributeName = "Training Complete - " + chapter;
- final Attribute attribute = new Attribute(attributeName);
- attribute.setStartDate(date);
- addAttribute(user, attribute);
- }
-
- private void addAttribute(final User user, final Attribute attribute) {
- if (!(user instanceof F1User)) {
- throw new IllegalArgumentException("User must be an F1User, but got " + user.getClass().getName());
- }
-
- try {
- final F1User f1User = (F1User) user;
- final F1API f1 = mF1Access.getAuthenticatedApi(f1User);
-
- if (!f1.addAttribute(user.getIdentifier(), attribute)) {
- LOG.error("addAttribute failed for " + user.getIdentifier() + " with attribute "
- + attribute.getAttributeName());
- }
- } catch (Exception e) {
- LOG.error("addAttribute failed for " + user.getIdentifier() + " with attribute "
- + attribute.getAttributeName(), e);
- }
- }
-}
diff --git a/src/com/p4square/f1oauth/F1User.java b/src/com/p4square/f1oauth/F1User.java
deleted file mode 100644
index e5ab487..0000000
--- a/src/com/p4square/f1oauth/F1User.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.f1oauth;
-
-import java.util.Map;
-
-import com.p4square.restlet.oauth.OAuthException;
-import com.p4square.restlet.oauth.OAuthUser;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class F1User extends OAuthUser {
- public static final String ID = "@id";
- public static final String FIRST_NAME = "firstName";
- public static final String LAST_NAME = "lastName";
- public static final String ICODE = "@iCode";
-
- private final Map mData;
-
- /**
- * Copy the user information from user into a new F1User.
- *
- * @param user Original user.
- * @param data F1 Person Record.
- * @throws IllegalStateException if data.get("person") is null.
- */
- public F1User(OAuthUser user, Map data) {
- super(user.getLocation(), user.getToken());
-
- mData = (Map) data.get("person");
- if (mData == null) {
- throw new IllegalStateException("Bad data");
- }
-
- setIdentifier(getString(ID));
- setFirstName(getString(FIRST_NAME));
- setLastName(getString(LAST_NAME));
- }
-
- /**
- * Get a String from the map.
- *
- * @param key The map key.
- * @return The value associated with the key, or null.
- */
- public String getString(String key) {
- Object blob = get(key);
-
- if (blob instanceof String) {
- return (String) blob;
-
- } else {
- return null;
- }
- }
-
- /**
- * Fetch an object from the F1 record.
- *
- * @param key The map key
- * @return The object in the map or null.
- */
- public Object get(String key) {
- return mData.get(key);
- }
-}
diff --git a/src/com/p4square/f1oauth/FellowshipOneIntegrationDriver.java b/src/com/p4square/f1oauth/FellowshipOneIntegrationDriver.java
deleted file mode 100644
index 865f5d6..0000000
--- a/src/com/p4square/f1oauth/FellowshipOneIntegrationDriver.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.p4square.f1oauth;
-
-import com.codahale.metrics.MetricRegistry;
-import com.p4square.grow.config.Config;
-import com.p4square.grow.frontend.IntegrationDriver;
-import com.p4square.grow.frontend.ProgressReporter;
-import org.restlet.Context;
-import org.restlet.security.Verifier;
-
-/**
- * The FellowshipOneIntegrationDriver creates implementations of various
- * objects to support integration with Fellowship One.
- */
-public class FellowshipOneIntegrationDriver implements IntegrationDriver {
-
- private final Context mContext;
- private final MetricRegistry mMetricRegistry;
- private final Config mConfig;
- private final F1Access mAPI;
-
- private final ProgressReporter mProgressReporter;
-
- public FellowshipOneIntegrationDriver(final Context context) {
- mContext = context;
- mConfig = (Config) context.getAttributes().get("com.p4square.grow.config");
- mMetricRegistry = (MetricRegistry) context.getAttributes().get("com.p4square.grow.metrics");
-
- mAPI = new F1Access(context,
- mConfig.getString("f1ConsumerKey", ""),
- mConfig.getString("f1ConsumerSecret", ""),
- mConfig.getString("f1BaseUrl", "staging.fellowshiponeapi.com"),
- mConfig.getString("f1ChurchCode", "pfseawa"),
- F1Access.UserType.WEBLINK);
- mAPI.setMetricRegistry(mMetricRegistry);
-
- mProgressReporter = new F1ProgressReporter(mAPI);
- }
-
- /**
- * @return An F1Access instance.
- */
- public F1Access getF1Access() {
- return mAPI;
- }
-
- @Override
- public Verifier newUserAuthenticationVerifier() {
- return new SecondPartyVerifier(mContext, mAPI);
- }
-
- @Override
- public ProgressReporter getProgressReporter() {
- return mProgressReporter;
- }
-}
diff --git a/src/com/p4square/f1oauth/SecondPartyAuthenticator.java b/src/com/p4square/f1oauth/SecondPartyAuthenticator.java
deleted file mode 100644
index 8deefec..0000000
--- a/src/com/p4square/f1oauth/SecondPartyAuthenticator.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.f1oauth;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.restlet.oauth.OAuthException;
-import com.p4square.restlet.oauth.OAuthUser;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.security.Authenticator;
-
-/**
- * Restlet Authenticator for 2nd
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SecondPartyAuthenticator extends Authenticator {
- private static final Logger LOG = Logger.getLogger(SecondPartyAuthenticator.class);
-
- private final F1Access mHelper;
-
- public SecondPartyAuthenticator(Context context, boolean optional, F1Access helper) {
- super(context, optional);
-
- mHelper = helper;
- }
-
- protected boolean authenticate(Request request, Response response) {
- if (request.getChallengeResponse() == null) {
- return false; // no credentials
- }
-
- String username = request.getChallengeResponse().getIdentifier();
- String password = new String(request.getChallengeResponse().getSecret());
-
- try {
- OAuthUser user = mHelper.getAccessToken(username, password);
- request.getClientInfo().setUser(user);
-
- return true;
-
- } catch (OAuthException e) {
- LOG.info("OAuth Exception: " + e);
- }
-
- return false; // Invalid credentials
- }
-}
diff --git a/src/com/p4square/f1oauth/SecondPartyVerifier.java b/src/com/p4square/f1oauth/SecondPartyVerifier.java
deleted file mode 100644
index 882c7e7..0000000
--- a/src/com/p4square/f1oauth/SecondPartyVerifier.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.f1oauth;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.restlet.oauth.OAuthException;
-import com.p4square.restlet.oauth.OAuthUser;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.Restlet;
-import org.restlet.data.Method;
-import org.restlet.data.Status;
-import org.restlet.ext.jackson.JacksonRepresentation;
-import org.restlet.security.Verifier;
-
-/**
- * Restlet Verifier for F1 2nd Party Authentication
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SecondPartyVerifier implements Verifier {
- private static final Logger LOG = Logger.getLogger(SecondPartyVerifier.class);
-
- private final Restlet mDispatcher;
- private final F1Access mHelper;
-
- public SecondPartyVerifier(Context context, F1Access helper) {
- if (helper == null) {
- throw new IllegalArgumentException("Helper can not be null.");
- }
-
- mDispatcher = context.getClientDispatcher();
- mHelper = helper;
- }
-
- @Override
- public int verify(Request request, Response response) {
- if (request.getChallengeResponse() == null) {
- return RESULT_MISSING; // no credentials
- }
-
- String username = request.getChallengeResponse().getIdentifier();
- String password = new String(request.getChallengeResponse().getSecret());
-
- try {
- OAuthUser ouser = mHelper.getAccessToken(username, password);
-
- // Once we have a user, fetch the people record to get the user id.
- F1User user = mHelper.getAuthenticatedApi(ouser).getF1User(ouser);
- user.setEmail(username);
-
- // This seems like a hack... but it'll work
- request.getClientInfo().setUser(user);
-
- return RESULT_VALID;
-
- } catch (Exception e) {
- LOG.info("OAuth Exception: " + e, e);
- }
-
- return RESULT_INVALID; // Invalid credentials
- }
-
-}
diff --git a/src/com/p4square/fmfacade/FMFacade.java b/src/com/p4square/fmfacade/FMFacade.java
deleted file mode 100644
index 0e552b0..0000000
--- a/src/com/p4square/fmfacade/FMFacade.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan <jesse@jesterpm.net>
- */
-
-package com.p4square.fmfacade;
-
-import java.io.IOException;
-
-import org.restlet.Application;
-import org.restlet.Component;
-import org.restlet.data.Protocol;
-import org.restlet.Restlet;
-import org.restlet.routing.Router;
-
-import freemarker.template.Configuration;
-import freemarker.template.DefaultObjectWrapper;
-import freemarker.template.Template;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.config.Config;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class FMFacade extends Application {
- private static final Logger cLog = Logger.getLogger(FMFacade.class);
- private final Configuration mFMConfig;
-
- public FMFacade() {
- mFMConfig = new Configuration();
- mFMConfig.setClassForTemplateLoading(getClass(), "/templates");
- mFMConfig.setObjectWrapper(new DefaultObjectWrapper());
- }
-
- /**
- * @return a Config object.
- */
- public Config getConfig() {
- return null;
- }
-
- @Override
- public synchronized Restlet createInboundRoot() {
- return createRouter();
- }
-
- /**
- * Retrieve a template.
- *
- * @param name The template name.
- * @return A FreeMarker template or null on error.
- */
- public Template getTemplate(String name) {
- try {
- return mFMConfig.getTemplate(name);
-
- } catch (IOException e) {
- cLog.error("Could not load template \"" + name + "\"", e);
- return null;
- }
- }
-
- /**
- * Create the router to be used by this application. This can be overriden
- * by sub-classes to add additional routes.
- *
- * @return The router.
- */
- protected Router createRouter() {
- Router router = new Router(getContext());
- router.attachDefault(FreeMarkerPageResource.class);
-
- return router;
- }
-
- /**
- * Stand-alone main for testing.
- */
- public static void main(String[] args) {
- // Start the HTTP Server
- final Component component = new Component();
- component.getServers().add(Protocol.HTTP, 8085);
- component.getClients().add(Protocol.HTTP);
- component.getDefaultHost().attach(new FMFacade());
-
- // Setup shutdown hook
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void run() {
- try {
- component.stop();
- } catch (Exception e) {
- cLog.error("Exception during cleanup", e);
- }
- }
- });
-
- cLog.info("Starting server...");
-
- try {
- component.start();
- } catch (Exception e) {
- cLog.fatal("Could not start: " + e.getMessage(), e);
- }
- }
-}
diff --git a/src/com/p4square/fmfacade/FreeMarkerPageResource.java b/src/com/p4square/fmfacade/FreeMarkerPageResource.java
deleted file mode 100644
index 8c8948a..0000000
--- a/src/com/p4square/fmfacade/FreeMarkerPageResource.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.fmfacade;
-
-import java.util.Map;
-import java.util.HashMap;
-
-import freemarker.template.Template;
-
-import org.restlet.Context;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ServerResource;
-import org.restlet.security.User;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.ftl.GetMethod;
-
-import com.p4square.session.Session;
-import com.p4square.session.Sessions;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class FreeMarkerPageResource extends ServerResource {
- private static Logger cLog = Logger.getLogger(FreeMarkerPageResource.class);
-
- public static Map<String, Object> baseRootObject(final Context context, final FMFacade fmf) {
- Map<String, Object> root = new HashMap<String, Object>();
-
- root.put("get", new GetMethod(context.getClientDispatcher()));
- root.put("config", fmf.getConfig());
-
- return root;
- }
-
- private FMFacade mFMF;
- private String mCurrentPage;
-
- @Override
- public void doInit() {
- mFMF = (FMFacade) getApplication();
- mCurrentPage = getReference().getRemainingPart(false, false);
- }
-
- protected Representation get() {
- try {
- Template t = mFMF.getTemplate("pages" + mCurrentPage + ".ftl");
-
- if (t == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- return new TemplateRepresentation(t, getRootObject(),
- MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- cLog.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-
- /**
- * Build and return the root object to pass to the FTL Template.
- * @return A map of objects and methods for the template to access.
- */
- protected Map<String, Object> getRootObject() {
- Map<String, Object> root = baseRootObject(getContext(), mFMF);
-
- root.put("attributes", getRequestAttributes());
- root.put("query", getQuery().getValuesMap());
-
- if (getClientInfo().isAuthenticated()) {
- final User user = getClientInfo().getUser();
- final Map<String, String> userMap = new HashMap<String, String>();
- userMap.put("id", user.getIdentifier());
- userMap.put("firstName", user.getFirstName());
- userMap.put("lastName", user.getLastName());
- userMap.put("email", user.getEmail());
- root.put("user", userMap);
- }
-
- Session s = Sessions.getInstance().get(getRequest());
- if (s != null) {
- root.put("session", s.getMap());
- }
-
- return root;
- }
-}
diff --git a/src/com/p4square/fmfacade/ftl/GetMethod.java b/src/com/p4square/fmfacade/ftl/GetMethod.java
deleted file mode 100644
index a47c4b0..0000000
--- a/src/com/p4square/fmfacade/ftl/GetMethod.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.fmfacade.ftl;
-
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-
-import java.io.IOException;
-
-import freemarker.core.Environment;
-import freemarker.template.SimpleScalar;
-import freemarker.template.TemplateMethodModel;
-import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.Status;
-import org.restlet.data.Method;
-import org.restlet.representation.Representation;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.Restlet;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-
-/**
- * This method allows templates to make GET requests.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class GetMethod implements TemplateMethodModel {
- private static final Logger cLog = Logger.getLogger(GetMethod.class);
-
- private final Restlet mDispatcher;
-
- public GetMethod(Restlet dispatcher) {
- mDispatcher = dispatcher;
- }
-
- /**
- * @param args List with exactly two arguments:
- * * The variable in which to put the result.
- * * The URI to GET.
- */
- public TemplateModel exec(List args) throws TemplateModelException {
- final Environment env = Environment.getCurrentEnvironment();
-
- if (args.size() != 2) {
- throw new TemplateModelException(
- "Expecting exactly one argument containing the URI");
- }
-
- Request request = new Request(Method.GET, (String) args.get(1));
- Response response = mDispatcher.handle(request);
- Status status = response.getStatus();
- Representation representation = response.getEntity();
-
- try {
- if (response.getStatus().isSuccess()) {
- JacksonRepresentation<Map> mapRepresentation;
- if (representation instanceof JacksonRepresentation) {
- mapRepresentation = (JacksonRepresentation<Map>) representation;
- } else {
- mapRepresentation = new JacksonRepresentation<Map>(
- representation, Map.class);
- }
- try {
- TemplateModel mapModel = env.getObjectWrapper().wrap(mapRepresentation.getObject());
-
- env.setVariable((String) args.get(0), mapModel);
-
- } catch (IOException e) {
- cLog.warn("Exception occurred when calling getObject(): "
- + e.getMessage(), e);
- status = Status.SERVER_ERROR_INTERNAL;
- }
- }
-
- Map statusMap = new HashMap();
- statusMap.put("code", status.getCode());
- statusMap.put("reason", status.getReasonPhrase());
- statusMap.put("succeeded", status.isSuccess());
- return env.getObjectWrapper().wrap(statusMap);
- } finally {
- if (representation != null) {
- representation.release();
- }
- }
- }
-}
diff --git a/src/com/p4square/fmfacade/json/ClientException.java b/src/com/p4square/fmfacade/json/ClientException.java
deleted file mode 100644
index c233193..0000000
--- a/src/com/p4square/fmfacade/json/ClientException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.fmfacade.json;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class ClientException extends Exception {
-
- public ClientException(final String msg) {
- super(msg);
- }
-
- public ClientException(final String msg, final Exception cause) {
- super(msg, cause);
- }
-}
diff --git a/src/com/p4square/fmfacade/json/JsonRequestClient.java b/src/com/p4square/fmfacade/json/JsonRequestClient.java
deleted file mode 100644
index 19a394f..0000000
--- a/src/com/p4square/fmfacade/json/JsonRequestClient.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.fmfacade.json;
-
-import java.util.Map;
-
-import java.io.IOException;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.data.Status;
-import org.restlet.data.Method;
-import org.restlet.representation.Representation;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.Restlet;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class JsonRequestClient {
- private final Restlet mDispatcher;
-
- public JsonRequestClient(Restlet dispatcher) {
- mDispatcher = dispatcher;
- }
-
- /**
- * Perform a GET request for the given URI and parse the response as a
- * JSON map.
- *
- * @return A JsonResponse object which can be used to retrieve the
- * response as a JSON map.
- */
- public JsonResponse get(final String uri) {
- final Request request = new Request(Method.GET, uri);
- final Response response = mDispatcher.handle(request);
-
- return new JsonResponse(response);
- }
-
- /**
- * Perform a PUT request for the given URI and parse the response as a
- * JSON map.
- *
- * @return A JsonResponse object which can be used to retrieve the
- * response as a JSON map.
- */
- public JsonResponse put(final String uri, Representation entity) {
- final Request request = new Request(Method.PUT, uri);
- request.setEntity(entity);
-
- final Response response = mDispatcher.handle(request);
- return new JsonResponse(response);
- }
-
- /**
- * Perform a PUT request for the given URI and parse the response as a
- * JSON map.
- *
- * @return A JsonResponse object which can be used to retrieve the
- * response as a JSON map.
- */
- public JsonResponse put(final String uri, Map map) {
- return put(uri, new JacksonRepresentation<Map>(map));
- }
-
- /**
- * Perform a POST request for the given URI and parse the response as a
- * JSON map.
- *
- * @return A JsonResponse object which can be used to retrieve the
- * response as a JSON map.
- */
- public JsonResponse post(final String uri, Representation entity) {
- final Request request = new Request(Method.POST, uri);
- request.setEntity(entity);
-
- final Response response = mDispatcher.handle(request);
- return new JsonResponse(response);
- }
-
- /**
- * Perform a POST request for the given URI and parse the response as a
- * JSON map.
- *
- * @return A JsonResponse object which can be used to retrieve the
- * response as a JSON map.
- */
- public JsonResponse post(final String uri, Map map) {
- return post(uri, new JacksonRepresentation<Map>(map));
- }
-
- /**
- * Perform a DELETE request for the given URI.
- *
- * @return A JsonResponse object with the status of the request.
- */
- public JsonResponse delete(final String uri) {
- final Request request = new Request(Method.DELETE, uri);
- final Response response = mDispatcher.handle(request);
- return new JsonResponse(response);
- }
-}
diff --git a/src/com/p4square/fmfacade/json/JsonResponse.java b/src/com/p4square/fmfacade/json/JsonResponse.java
deleted file mode 100644
index b9cb587..0000000
--- a/src/com/p4square/fmfacade/json/JsonResponse.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.fmfacade.json;
-
-import java.util.Map;
-
-import java.io.IOException;
-
-import org.restlet.data.Status;
-import org.restlet.data.Reference;
-import org.restlet.representation.Representation;
-import org.restlet.Response;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-
-/**
- * JsonResponse wraps a Restlet Response object and parses the entity, if any,
- * as a JSON map.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class JsonResponse {
- private final Response mResponse;
- private final Representation mRepresentation;
-
- private Map<String, Object> mMap;
-
- JsonResponse(Response response) {
- mResponse = response;
- mRepresentation = response.getEntity();
- mMap = null;
-
- if (!response.getStatus().isSuccess()) {
- if (mRepresentation != null) {
- mRepresentation.release();
- }
- }
- }
-
- /**
- * @return the Status info from the response.
- */
- public Status getStatus() {
- return mResponse.getStatus();
- }
-
- /**
- * @return the Reference for a redirect.
- */
- public Reference getRedirectLocation() {
- return mResponse.getLocationRef();
- }
-
- /**
- * Return the parsed json map from the response.
- */
- public Map<String, Object> getMap() throws ClientException {
- if (mMap == null) {
- Representation representation = mRepresentation;
-
- // Parse response
- if (representation == null) {
- return null;
- }
-
- JacksonRepresentation<Map> mapRepresentation;
- if (representation instanceof JacksonRepresentation) {
- mapRepresentation = (JacksonRepresentation<Map>) representation;
- } else {
- mapRepresentation = new JacksonRepresentation<Map>(
- representation, Map.class);
- }
-
- try {
- mMap = (Map<String, Object>) mapRepresentation.getObject();
-
- } catch (IOException e) {
- throw new ClientException("Failed to parse response: " + e.getMessage(), e);
- }
- }
-
- return mMap;
- }
-
-}
diff --git a/src/com/p4square/grow/GrowProcessComponent.java b/src/com/p4square/grow/GrowProcessComponent.java
deleted file mode 100644
index f63538c..0000000
--- a/src/com/p4square/grow/GrowProcessComponent.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-import com.codahale.metrics.ConsoleReporter;
-import com.codahale.metrics.MetricRegistry;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Application;
-import org.restlet.Component;
-import org.restlet.Restlet;
-import org.restlet.data.ChallengeScheme;
-import org.restlet.data.Protocol;
-import org.restlet.resource.Directory;
-import org.restlet.security.ChallengeAuthenticator;
-
-import com.p4square.grow.backend.BackendVerifier;
-import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.config.Config;
-import com.p4square.grow.frontend.GrowFrontend;
-import com.p4square.restlet.metrics.MetricsApplication;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class GrowProcessComponent extends Component {
- private static Logger LOG = Logger.getLogger(GrowProcessComponent.class);
-
- private static final String BACKEND_REALM = "Grow Backend";
-
- private final Config mConfig;
- private final MetricRegistry mMetricRegistry;
-
- /**
- * Create a new Grow Process website component combining a frontend and backend.
- */
- public GrowProcessComponent() throws Exception {
- this(new Config());
- }
-
- public GrowProcessComponent(Config config) throws Exception {
- // Clients
- getClients().add(Protocol.FILE);
- getClients().add(Protocol.HTTP);
- getClients().add(Protocol.HTTPS);
-
- // Prepare mConfig
- mConfig = config;
- mConfig.updateConfig(this.getClass().getResourceAsStream("/grow.properties"));
-
- // Prepare Metrics
- mMetricRegistry = new MetricRegistry();
-
- // Frontend
- GrowFrontend frontend = new GrowFrontend(mConfig, mMetricRegistry);
- getDefaultHost().attach(frontend);
-
- // Backend
- GrowBackend backend = new GrowBackend(mConfig, mMetricRegistry);
- getInternalRouter().attach("/backend", backend);
-
- // Authenticated access to the backend
- BackendVerifier verifier = new BackendVerifier(backend.getUserRecordProvider());
- ChallengeAuthenticator auth = new ChallengeAuthenticator(getContext().createChildContext(),
- false, ChallengeScheme.HTTP_BASIC, BACKEND_REALM, verifier);
- auth.setNext(backend);
- getDefaultHost().attach("/backend", auth);
-
- // Authenticated access to metrics
- ChallengeAuthenticator metricAuth = new ChallengeAuthenticator(
- getContext().createChildContext(), false,
- ChallengeScheme.HTTP_BASIC, BACKEND_REALM, verifier);
- metricAuth.setNext(new MetricsApplication(mMetricRegistry));
- getDefaultHost().attach("/metrics", metricAuth);
- }
-
-
- @Override
- public void start() throws Exception {
- String configDomain = getContext().getParameters().getFirstValue("com.p4square.grow.configDomain");
- if (configDomain != null) {
- mConfig.setDomain(configDomain);
- }
-
- String configFilename = getContext().getParameters().getFirstValue("com.p4square.grow.configFile");
- if (configFilename != null) {
- mConfig.updateConfig(configFilename);
- }
-
- super.start();
- }
-
- /**
- * Stand-alone main for testing.
- */
- public static void main(String[] args) throws Exception {
- // Load an optional config file from the first argument.
- Config config = new Config();
- config.setDomain("dev");
- if (args.length >= 1) {
- config.updateConfig(args[0]);
- }
-
- // Override domain
- if (args.length == 2) {
- config.setDomain(args[1]);
- }
-
- // Start the HTTP Server
- final GrowProcessComponent component = new GrowProcessComponent(config);
- component.getServers().add(Protocol.HTTP, 8085);
-
- // Static content
- try {
- component.getDefaultHost().attach("/images/", new FileServingApp("./build/root/images/"));
- component.getDefaultHost().attach("/scripts", new FileServingApp("./build/root/scripts"));
- component.getDefaultHost().attach("/style.css", new FileServingApp("./build/root/style.css"));
- component.getDefaultHost().attach("/favicon.ico", new FileServingApp("./build/root/favicon.ico"));
- component.getDefaultHost().attach("/notfound.html", new FileServingApp("./build/root/notfound.html"));
- component.getDefaultHost().attach("/error.html", new FileServingApp("./build/root/error.html"));
- } catch (IOException e) {
- LOG.error("Could not create directory for static resources: "
- + e.getMessage(), e);
- }
-
- // Setup shutdown hook
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void run() {
- try {
- component.stop();
- } catch (Exception e) {
- LOG.error("Exception during cleanup", e);
- }
- }
- });
-
- LOG.info("Starting server...");
-
- try {
- component.start();
- } catch (Exception e) {
- LOG.fatal("Could not start: " + e.getMessage(), e);
- }
- }
-
- private static class FileServingApp extends Application {
- private final String mPath;
-
- public FileServingApp(String path) throws IOException {
- mPath = new File(path).getAbsolutePath();
- }
-
- @Override
- public Restlet createInboundRoot() {
- return new Directory(getContext(), "file://" + mPath);
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/BackendVerifier.java b/src/com/p4square/grow/backend/BackendVerifier.java
deleted file mode 100644
index 83160a9..0000000
--- a/src/com/p4square/grow/backend/BackendVerifier.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend;
-
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import org.apache.commons.codec.binary.Hex;
-
-import org.restlet.security.SecretVerifier;
-
-import com.p4square.grow.model.UserRecord;
-import com.p4square.grow.provider.Provider;
-
-/**
- * Verify the given credentials against the users with backend access.
- */
-public class BackendVerifier extends SecretVerifier {
-
- private final Provider<String, UserRecord> mUserProvider;
-
- public BackendVerifier(Provider<String, UserRecord> userProvider) {
- mUserProvider = userProvider;
- }
-
- @Override
- public int verify(String identifier, char[] secret) {
- if (identifier == null) {
- throw new IllegalArgumentException("Null identifier");
- }
-
- if (secret == null) {
- throw new IllegalArgumentException("Null secret");
- }
-
- // Does the user exist?
- UserRecord user;
- try {
- user = mUserProvider.get(identifier);
- if (user == null) {
- return RESULT_UNKNOWN;
- }
-
- } catch (IOException e) {
- return RESULT_UNKNOWN;
- }
-
- // Does the user have a backend password?
- String storedHash = user.getBackendPasswordHash();
- if (storedHash == null) {
- // This user doesn't have access
- return RESULT_INVALID;
- }
-
- // Validate the password.
- try {
- String hashedInput = hashPassword(secret);
- if (hashedInput.equals(storedHash)) {
- return RESULT_VALID;
- }
-
- } catch (NoSuchAlgorithmException e) {
- return RESULT_UNSUPPORTED;
- }
-
- // If all else fails, fail.
- return RESULT_INVALID;
- }
-
- /**
- * Hash the given secret.
- */
- public static String hashPassword(char[] secret) throws NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance("SHA-1");
-
- // Convert the char[] to byte[]
- // FIXME This approach is incorrectly truncating multibyte
- // characters.
- byte[] b = new byte[secret.length];
- for (int i = 0; i < secret.length; i++) {
- b[i] = (byte) secret[i];
- }
-
- md.update(b);
-
- byte[] hash = md.digest();
- return new String(Hex.encodeHex(hash));
- }
-}
diff --git a/src/com/p4square/grow/backend/CassandraGrowData.java b/src/com/p4square/grow/backend/CassandraGrowData.java
deleted file mode 100644
index 22a7716..0000000
--- a/src/com/p4square/grow/backend/CassandraGrowData.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend;
-
-import java.io.IOException;
-
-import com.p4square.grow.config.Config;
-
-import com.p4square.grow.backend.db.CassandraDatabase;
-import com.p4square.grow.backend.db.CassandraKey;
-import com.p4square.grow.backend.db.CassandraProviderImpl;
-import com.p4square.grow.backend.db.CassandraCollectionProvider;
-import com.p4square.grow.backend.db.CassandraTrainingRecordProvider;
-
-import com.p4square.grow.model.Message;
-import com.p4square.grow.model.MessageThread;
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.model.Question;
-import com.p4square.grow.model.TrainingRecord;
-import com.p4square.grow.model.UserRecord;
-
-import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.DelegateCollectionProvider;
-import com.p4square.grow.provider.DelegateProvider;
-import com.p4square.grow.provider.Provider;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-class CassandraGrowData implements GrowData {
- private static final String DEFAULT_COLUMN = "value";
-
- private final Config mConfig;
- private final CassandraDatabase mDatabase;
-
- private final Provider<String, UserRecord> mUserRecordProvider;
-
- private final Provider<String, Question> mQuestionProvider;
- private final CassandraTrainingRecordProvider mTrainingRecordProvider;
- private final CollectionProvider<String, String, String> mVideoProvider;
-
- private final CollectionProvider<String, String, MessageThread> mFeedThreadProvider;
- private final CollectionProvider<String, String, Message> mFeedMessageProvider;
-
- private final Provider<String, String> mStringProvider;
-
- private final CollectionProvider<String, String, String> mAnswerProvider;
-
- public CassandraGrowData(final Config config) {
- mConfig = config;
- mDatabase = new CassandraDatabase();
-
- mUserRecordProvider = new DelegateProvider<String, CassandraKey, UserRecord>(
- new CassandraProviderImpl<UserRecord>(mDatabase, UserRecord.class)) {
- @Override
- public CassandraKey makeKey(String userid) {
- return new CassandraKey("accounts", userid, DEFAULT_COLUMN);
- }
- };
-
- mQuestionProvider = new DelegateProvider<String, CassandraKey, Question>(
- new CassandraProviderImpl<Question>(mDatabase, Question.class)) {
- @Override
- public CassandraKey makeKey(String questionId) {
- return new CassandraKey("strings", "/questions/" + questionId, DEFAULT_COLUMN);
- }
- };
-
- mFeedThreadProvider = new CassandraCollectionProvider<MessageThread>(mDatabase,
- "feedthreads", MessageThread.class);
- mFeedMessageProvider = new CassandraCollectionProvider<Message>(mDatabase,
- "feedmessages", Message.class);
-
- mTrainingRecordProvider = new CassandraTrainingRecordProvider(mDatabase);
-
- mVideoProvider = new DelegateCollectionProvider<String, String, String, String, String>(
- new CassandraCollectionProvider<String>(mDatabase, "strings", String.class)) {
- @Override
- public String makeCollectionKey(String key) {
- return "/training/" + key;
- }
-
- @Override
- public String makeKey(String key) {
- return key;
- }
-
- @Override
- public String unmakeKey(String key) {
- return key;
- }
- };
-
- mStringProvider = new DelegateProvider<String, CassandraKey, String>(
- new CassandraProviderImpl<String>(mDatabase, String.class)) {
- @Override
- public CassandraKey makeKey(String id) {
- return new CassandraKey("strings", id, DEFAULT_COLUMN);
- }
- };
-
- mAnswerProvider = new CassandraCollectionProvider<String>(
- mDatabase, "assessments", String.class);
- }
-
- @Override
- public void start() throws Exception {
- mDatabase.setClusterName(mConfig.getString("clusterName", "Dev Cluster"));
- mDatabase.setKeyspaceName(mConfig.getString("keyspace", "GROW"));
- mDatabase.init();
- }
-
- @Override
- public void stop() throws Exception {
- mDatabase.close();
- }
-
- /**
- * @return the current database.
- */
- public CassandraDatabase getDatabase() {
- return mDatabase;
- }
-
- @Override
- public Provider<String, UserRecord> getUserRecordProvider() {
- return mUserRecordProvider;
- }
-
- @Override
- public Provider<String, Question> getQuestionProvider() {
- return mQuestionProvider;
- }
-
- @Override
- public Provider<String, TrainingRecord> getTrainingRecordProvider() {
- return mTrainingRecordProvider;
- }
-
- @Override
- public CollectionProvider<String, String, String> getVideoProvider() {
- return mVideoProvider;
- }
-
- @Override
- public Playlist getDefaultPlaylist() throws IOException {
- return mTrainingRecordProvider.getDefaultPlaylist();
- }
-
- @Override
- public CollectionProvider<String, String, MessageThread> getThreadProvider() {
- return mFeedThreadProvider;
- }
-
- @Override
- public CollectionProvider<String, String, Message> getMessageProvider() {
- return mFeedMessageProvider;
- }
-
- @Override
- public Provider<String, String> getStringProvider() {
- return mStringProvider;
- }
-
- @Override
- public CollectionProvider<String, String, String> getAnswerProvider() {
- return mAnswerProvider;
- }
-}
diff --git a/src/com/p4square/grow/backend/DynamoGrowData.java b/src/com/p4square/grow/backend/DynamoGrowData.java
deleted file mode 100644
index 3b38eac..0000000
--- a/src/com/p4square/grow/backend/DynamoGrowData.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend;
-
-import java.io.IOException;
-
-import com.amazonaws.auth.AWSCredentials;
-
-import com.p4square.grow.backend.dynamo.DynamoDatabase;
-import com.p4square.grow.backend.dynamo.DynamoKey;
-import com.p4square.grow.backend.dynamo.DynamoProviderImpl;
-import com.p4square.grow.backend.dynamo.DynamoCollectionProviderImpl;
-
-import com.p4square.grow.config.Config;
-
-import com.p4square.grow.model.Message;
-import com.p4square.grow.model.MessageThread;
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.model.Question;
-import com.p4square.grow.model.TrainingRecord;
-import com.p4square.grow.model.UserRecord;
-
-import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.DelegateCollectionProvider;
-import com.p4square.grow.provider.DelegateProvider;
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-class DynamoGrowData implements GrowData {
- private static final String DEFAULT_COLUMN = "value";
- private static final String DEFAULT_PLAYLIST_KEY = "/training/defaultplaylist";
-
- private final Config mConfig;
- private final DynamoDatabase mDatabase;
-
- private final Provider<String, UserRecord> mUserRecordProvider;
-
- private final Provider<String, Question> mQuestionProvider;
- private final Provider<String, TrainingRecord> mTrainingRecordProvider;
- private final CollectionProvider<String, String, String> mVideoProvider;
-
- private final CollectionProvider<String, String, MessageThread> mFeedThreadProvider;
- private final CollectionProvider<String, String, Message> mFeedMessageProvider;
-
- private final Provider<String, String> mStringProvider;
-
- private final CollectionProvider<String, String, String> mAnswerProvider;
-
- public DynamoGrowData(final Config config) {
- mConfig = config;
-
- mDatabase = new DynamoDatabase(config);
-
- mUserRecordProvider = new DelegateProvider<String, DynamoKey, UserRecord>(
- new DynamoProviderImpl<UserRecord>(mDatabase, UserRecord.class)) {
- @Override
- public DynamoKey makeKey(String userid) {
- return DynamoKey.newAttributeKey("accounts", userid, DEFAULT_COLUMN);
- }
- };
-
- mQuestionProvider = new DelegateProvider<String, DynamoKey, Question>(
- new DynamoProviderImpl<Question>(mDatabase, Question.class)) {
- @Override
- public DynamoKey makeKey(String questionId) {
- return DynamoKey.newAttributeKey("strings",
- "/questions/" + questionId,
- DEFAULT_COLUMN);
- }
- };
-
- mFeedThreadProvider = new DynamoCollectionProviderImpl<MessageThread>(
- mDatabase, "feedthreads", MessageThread.class);
- mFeedMessageProvider = new DynamoCollectionProviderImpl<Message>(
- mDatabase, "feedmessages", Message.class);
-
- mTrainingRecordProvider = new DelegateProvider<String, DynamoKey, TrainingRecord>(
- new DynamoProviderImpl<TrainingRecord>(mDatabase, TrainingRecord.class)) {
- @Override
- public DynamoKey makeKey(String userId) {
- return DynamoKey.newAttributeKey("training",
- userId,
- DEFAULT_COLUMN);
- }
- };
-
- mVideoProvider = new DelegateCollectionProvider<String, String, String, String, String>(
- new DynamoCollectionProviderImpl<String>(mDatabase, "strings", String.class)) {
- @Override
- public String makeCollectionKey(String key) {
- return "/training/" + key;
- }
-
- @Override
- public String makeKey(String key) {
- return key;
- }
-
- @Override
- public String unmakeKey(String key) {
- return key;
- }
- };
-
- mStringProvider = new DelegateProvider<String, DynamoKey, String>(
- new DynamoProviderImpl<String>(mDatabase, String.class)) {
- @Override
- public DynamoKey makeKey(String id) {
- return DynamoKey.newAttributeKey("strings", id, DEFAULT_COLUMN);
- }
- };
-
- mAnswerProvider = new DynamoCollectionProviderImpl<String>(
- mDatabase, "assessments", String.class);
- }
-
- @Override
- public void start() throws Exception {
- }
-
- @Override
- public void stop() throws Exception {
- }
-
- @Override
- public Provider<String, UserRecord> getUserRecordProvider() {
- return mUserRecordProvider;
- }
-
- @Override
- public Provider<String, Question> getQuestionProvider() {
- return mQuestionProvider;
- }
-
- @Override
- public Provider<String, TrainingRecord> getTrainingRecordProvider() {
- return mTrainingRecordProvider;
- }
-
- @Override
- public CollectionProvider<String, String, String> getVideoProvider() {
- return mVideoProvider;
- }
-
- @Override
- public Playlist getDefaultPlaylist() throws IOException {
- String blob = mStringProvider.get(DEFAULT_PLAYLIST_KEY);
- if (blob == null) {
- return null;
- }
-
- return JsonEncodedProvider.MAPPER.readValue(blob, Playlist.class);
- }
-
- @Override
- public CollectionProvider<String, String, MessageThread> getThreadProvider() {
- return mFeedThreadProvider;
- }
-
- @Override
- public CollectionProvider<String, String, Message> getMessageProvider() {
- return mFeedMessageProvider;
- }
-
- @Override
- public Provider<String, String> getStringProvider() {
- return mStringProvider;
- }
-
- @Override
- public CollectionProvider<String, String, String> getAnswerProvider() {
- return mAnswerProvider;
- }
-}
diff --git a/src/com/p4square/grow/backend/GrowBackend.java b/src/com/p4square/grow/backend/GrowBackend.java
deleted file mode 100644
index 4091138..0000000
--- a/src/com/p4square/grow/backend/GrowBackend.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright 2012 Jesse Morgan
- */
-
-package com.p4square.grow.backend;
-
-import java.io.IOException;
-
-import com.codahale.metrics.MetricRegistry;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Application;
-import org.restlet.Component;
-import org.restlet.Restlet;
-import org.restlet.data.Protocol;
-import org.restlet.data.Reference;
-import org.restlet.resource.Directory;
-import org.restlet.routing.Router;
-
-import com.p4square.grow.config.Config;
-
-import com.p4square.grow.model.Message;
-import com.p4square.grow.model.MessageThread;
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.model.Question;
-import com.p4square.grow.model.TrainingRecord;
-import com.p4square.grow.model.UserRecord;
-
-import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.ProvidesQuestions;
-import com.p4square.grow.provider.ProvidesTrainingRecords;
-import com.p4square.grow.provider.ProvidesUserRecords;
-
-import com.p4square.grow.backend.resources.AccountResource;
-import com.p4square.grow.backend.resources.BannerResource;
-import com.p4square.grow.backend.resources.SurveyResource;
-import com.p4square.grow.backend.resources.SurveyResultsResource;
-import com.p4square.grow.backend.resources.TrainingRecordResource;
-import com.p4square.grow.backend.resources.TrainingResource;
-
-import com.p4square.grow.backend.feed.FeedDataProvider;
-import com.p4square.grow.backend.feed.ThreadResource;
-import com.p4square.grow.backend.feed.TopicResource;
-
-import com.p4square.restlet.metrics.MetricRouter;
-
-/**
- * Main class for the backend application.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class GrowBackend extends Application implements GrowData {
-
- private final static Logger LOG = Logger.getLogger(GrowBackend.class);
-
- private final MetricRegistry mMetricRegistry;
-
- private final Config mConfig;
- private final GrowData mGrowData;
-
- public GrowBackend() {
- this(new Config(), new MetricRegistry());
- }
-
- public GrowBackend(Config config, MetricRegistry metricRegistry) {
- mConfig = config;
-
- mMetricRegistry = metricRegistry;
-
- mGrowData = new DynamoGrowData(config);
- }
-
- public MetricRegistry getMetrics() {
- return mMetricRegistry;
- }
-
- @Override
- public Restlet createInboundRoot() {
- Router router = new MetricRouter(getContext(), mMetricRegistry);
-
- // Account API
- router.attach("/accounts/{userId}", AccountResource.class);
-
- // Survey API
- router.attach("/assessment/question/{questionId}", SurveyResource.class);
-
- router.attach("/accounts/{userId}/assessment", SurveyResultsResource.class);
- router.attach("/accounts/{userId}/assessment/answers/{questionId}",
- SurveyResultsResource.class);
-
- // Training API
- router.attach("/training/{level}", TrainingResource.class);
- router.attach("/training/{level}/videos/{videoId}", TrainingResource.class);
-
- router.attach("/accounts/{userId}/training", TrainingRecordResource.class);
- router.attach("/accounts/{userId}/training/videos/{videoId}",
- TrainingRecordResource.class);
-
- // Misc.
- router.attach("/banner", BannerResource.class);
-
- // Feed
- router.attach("/feed/{topic}", TopicResource.class);
- router.attach("/feed/{topic}/{thread}", ThreadResource.class);
- //router.attach("/feed/{topic/{thread}/{message}", MessageResource.class);
-
- router.attachDefault(new Directory(getContext(), new Reference(getClass().getResource("apiinfo.html"))));
-
- return router;
- }
-
- /**
- * Open the database.
- */
- @Override
- public void start() throws Exception {
- super.start();
-
- mGrowData.start();
- }
-
- /**
- * Close the database.
- */
- @Override
- public void stop() throws Exception {
- LOG.info("Shutting down...");
- mGrowData.stop();
-
- super.stop();
- }
-
- @Override
- public Provider<String, UserRecord> getUserRecordProvider() {
- return mGrowData.getUserRecordProvider();
- }
-
- @Override
- public Provider<String, Question> getQuestionProvider() {
- return mGrowData.getQuestionProvider();
- }
-
- @Override
- public CollectionProvider<String, String, String> getVideoProvider() {
- return mGrowData.getVideoProvider();
- }
-
- @Override
- public Provider<String, TrainingRecord> getTrainingRecordProvider() {
- return mGrowData.getTrainingRecordProvider();
- }
-
- /**
- * @return the Default Playlist.
- */
- public Playlist getDefaultPlaylist() throws IOException {
- return mGrowData.getDefaultPlaylist();
- }
-
- @Override
- public CollectionProvider<String, String, MessageThread> getThreadProvider() {
- return mGrowData.getThreadProvider();
- }
-
- @Override
- public CollectionProvider<String, String, Message> getMessageProvider() {
- return mGrowData.getMessageProvider();
- }
-
- @Override
- public Provider<String, String> getStringProvider() {
- return mGrowData.getStringProvider();
- }
-
- @Override
- public CollectionProvider<String, String, String> getAnswerProvider() {
- return mGrowData.getAnswerProvider();
- }
-
- /**
- * Stand-alone main for testing.
- */
- public static void main(String[] args) throws Exception {
- // Start the HTTP Server
- final Component component = new Component();
- component.getServers().add(Protocol.HTTP, 9095);
- component.getClients().add(Protocol.HTTP);
- component.getDefaultHost().attach(new GrowBackend());
-
- // Setup shutdown hook
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void run() {
- try {
- component.stop();
- } catch (Exception e) {
- LOG.error("Exception during cleanup", e);
- }
- }
- });
-
- LOG.info("Starting server...");
-
- try {
- component.start();
- } catch (Exception e) {
- LOG.fatal("Could not start: " + e.getMessage(), e);
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/GrowData.java b/src/com/p4square/grow/backend/GrowData.java
deleted file mode 100644
index 293bb88..0000000
--- a/src/com/p4square/grow/backend/GrowData.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend;
-
-import com.p4square.grow.backend.feed.FeedDataProvider;
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.provider.ProvidesAssessments;
-import com.p4square.grow.provider.ProvidesQuestions;
-import com.p4square.grow.provider.ProvidesStrings;
-import com.p4square.grow.provider.ProvidesTrainingRecords;
-import com.p4square.grow.provider.ProvidesUserRecords;
-import com.p4square.grow.provider.ProvidesVideos;
-
-/**
- * Aggregate of the data provider interfaces.
- *
- * Used by GrowBackend to swap out implementations of the providers.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-interface GrowData extends ProvidesQuestions, ProvidesTrainingRecords, ProvidesVideos,
- FeedDataProvider, ProvidesUserRecords, ProvidesStrings,
- ProvidesAssessments {
-
- /**
- * Start the data provider.
- */
- void start() throws Exception;
-
- /**
- * Stop the data provider.
- */
- void stop() throws Exception;
-}
diff --git a/src/com/p4square/grow/backend/apiinfo.html b/src/com/p4square/grow/backend/apiinfo.html
deleted file mode 100644
index a3637c9..0000000
--- a/src/com/p4square/grow/backend/apiinfo.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<html>
-<head>
-<title>API Info</title>
-</head>
-<body>
-<dl>
-<dt>/backend/accounts/{userId}</dt>
-<dd>GET information about <em>userId</em> or PUT new information.</dd>
-
-<dt>/backend/assessment/question/{questionId}</dt>
-<dd>GET information about <em>questionId</em>. Special <em>questionId</em>s: first identifies first question. count returns total number of questions.</dd>
-
-<dt>/backend/accounts/{userId}/assessment</dt>
-<dd>GET the assessment summary for <em>userId</em> or DELETE <em>userId</em>'s assessment.</dd>
-
-<dt>/backend/accounts/{userId}/assessment/answers/{questionId}</dt>
-<dd>GET <em>userId</em>'s answer to <em>questionId</em>, PUT a new answer, or DELETE an answer.</dd>
-
-<dt>/backend/training/{level}</dt>
-<dd>GET all video information for <em>level</em>.</dd>
-
-<dt>/backend/training/{level}/videos/{videoId}</dt>
-<dd>GET video information for <em>videoId</em> in <em>level</em>.</dd>
-
-<dt>/backend/accounts/{userId}/training</dt>
-<dd>GET training record summary for <em>userId</em>.</dd>
-
-<dt>/backend/accounts/{userId}/training/videos/{videoId}</dt>
-<dd>GET training record for <em>userId</em> and <em>videoId</em> or PUT a new record.</dd>
-
-<dt>/backend/banner</dt>
-<dd>GET the info banner or PUT new banner info.</dd>
-
-<dt>/backend/feed/{topic}</dt>
-<dd>Get all threads for forum <em>topic</em>.</dd>
-
-<dt>/backend/feed/{topic}/{thread}</dt>
-<dd>Get all responses to question <em>thread</em> on forum <em>topic</em>.</dd>
-</dl>
-</body>
-</html>
diff --git a/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java b/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java
deleted file mode 100644
index bfcb48d..0000000
--- a/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.db;
-
-import java.io.IOException;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import com.netflix.astyanax.model.Column;
-import com.netflix.astyanax.model.ColumnList;
-
-import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- * CollectionProvider implementation backed by a Cassandra ColumnFamily.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class CassandraCollectionProvider<V> implements CollectionProvider<String, String, V> {
- private final CassandraDatabase mDb;
- private final String mCF;
- private final Class<V> mClazz;
-
- public CassandraCollectionProvider(CassandraDatabase db, String columnFamily, Class<V> clazz) {
- mDb = db;
- mCF = columnFamily;
- mClazz = clazz;
- }
-
- @Override
- public V get(String collection, String key) throws IOException {
- String blob = mDb.getKey(mCF, collection, key);
- return decode(blob);
- }
-
- @Override
- public Map<String, V> query(String collection) throws IOException {
- return query(collection, -1);
- }
-
- @Override
- public Map<String, V> query(String collection, int limit) throws IOException {
- Map<String, V> result = new LinkedHashMap<>();
-
- ColumnList<String> row = mDb.getRow(mCF, collection);
- if (!row.isEmpty()) {
- int count = 0;
- for (Column<String> c : row) {
- if (limit >= 0 && ++count > limit) {
- break; // Limit reached.
- }
-
- String key = c.getName();
- String blob = c.getStringValue();
- V obj = decode(blob);
-
- result.put(key, obj);
- }
- }
-
- return Collections.unmodifiableMap(result);
- }
-
- @Override
- public void put(String collection, String key, V obj) throws IOException {
- String blob = encode(obj);
- mDb.putKey(mCF, collection, key, blob);
- }
-
- /**
- * Encode the object as JSON.
- *
- * @param obj The object to encode.
- * @return The JSON encoding of obj.
- * @throws IOException if the object cannot be encoded.
- */
- protected String encode(V obj) throws IOException {
- if (mClazz == String.class) {
- return (String) obj;
- } else {
- return JsonEncodedProvider.MAPPER.writeValueAsString(obj);
- }
- }
-
- /**
- * Decode the JSON string as an object.
- *
- * @param blob The JSON data to decode.
- * @return The decoded object or null if blob is null.
- * @throws IOException If an object cannot be decoded.
- */
- protected V decode(String blob) throws IOException {
- if (blob == null) {
- return null;
- }
-
- if (mClazz == String.class) {
- return (V) blob;
- }
-
- V obj = JsonEncodedProvider.MAPPER.readValue(blob, mClazz);
- return obj;
- }
-}
diff --git a/src/com/p4square/grow/backend/db/CassandraDatabase.java b/src/com/p4square/grow/backend/db/CassandraDatabase.java
deleted file mode 100644
index b8cb6df..0000000
--- a/src/com/p4square/grow/backend/db/CassandraDatabase.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.db;
-
-import com.netflix.astyanax.AstyanaxContext;
-import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
-import com.netflix.astyanax.connectionpool.impl.ConnectionPoolConfigurationImpl;
-import com.netflix.astyanax.connectionpool.impl.CountingConnectionPoolMonitor;
-import com.netflix.astyanax.connectionpool.NodeDiscoveryType;
-import com.netflix.astyanax.connectionpool.OperationResult;
-import com.netflix.astyanax.impl.AstyanaxConfigurationImpl;
-import com.netflix.astyanax.Keyspace;
-import com.netflix.astyanax.ColumnMutation;
-import com.netflix.astyanax.model.Column;
-import com.netflix.astyanax.model.ColumnFamily;
-import com.netflix.astyanax.model.ColumnList;
-import com.netflix.astyanax.ColumnListMutation;
-import com.netflix.astyanax.MutationBatch;
-import com.netflix.astyanax.serializers.StringSerializer;
-import com.netflix.astyanax.thrift.ThriftFamilyFactory;
-
-import org.apache.log4j.Logger;
-
-/**
- * Cassandra Database Abstraction for the Backend.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class CassandraDatabase {
- private static Logger cLog = Logger.getLogger(CassandraDatabase.class);
-
- // Configuration fields.
- private String mClusterName;
- private String mKeyspaceName;
- private String mSeedEndpoint = "127.0.0.1:9160";
- private int mPort = 9160;
-
- private AstyanaxContext<Keyspace> mContext;
- private Keyspace mKeyspace;
-
- /**
- * Connect to Cassandra.
- *
- * Cluster and Keyspace must be set before calling init().
- */
- public void init() {
- mContext = new AstyanaxContext.Builder()
- .forCluster(mClusterName)
- .forKeyspace(mKeyspaceName)
- .withAstyanaxConfiguration(new AstyanaxConfigurationImpl()
- .setDiscoveryType(NodeDiscoveryType.RING_DESCRIBE)
- )
- .withConnectionPoolConfiguration(new ConnectionPoolConfigurationImpl("MyConnectionPool")
- .setPort(mPort)
- .setMaxConnsPerHost(1)
- .setSeeds(mSeedEndpoint)
- )
- .withConnectionPoolMonitor(new CountingConnectionPoolMonitor())
- .buildKeyspace(ThriftFamilyFactory.getInstance());
-
- mContext.start();
- mKeyspace = mContext.getClient();
- }
-
- /**
- * Close the database connection.
- */
- public void close() {
- mContext.shutdown();
- }
-
- /**
- * Set the cluster name to connect to.
- */
- public void setClusterName(final String cluster) {
- mClusterName = cluster;
- }
-
- /**
- * Set the name of the keyspace to open.
- */
- public void setKeyspaceName(final String keyspace) {
- mKeyspaceName = keyspace;
- }
-
- /**
- * Change the seed endpoint.
- * The default is 127.0.0.1:9160.
- */
- public void setSeedEndpoint(final String endpoint) {
- mSeedEndpoint = endpoint;
- }
-
- /**
- * Change the port to connect to.
- * The default is 9160.
- */
- public void setPort(final int port) {
- mPort = port;
- }
-
- /**
- * @return The entire row associated with this key.
- */
- public ColumnList<String> getRow(final String cfName, final String key) {
- try {
- ColumnFamily<String, String> cf = new ColumnFamily(cfName,
- StringSerializer.get(),
- StringSerializer.get());
-
- OperationResult<ColumnList<String>> result =
- mKeyspace.prepareQuery(cf)
- .getKey(key)
- .execute();
-
- return result.getResult();
-
- } catch (ConnectionException e) {
- cLog.error("getRow failed due to Connection Exception", e);
- throw new RuntimeException(e);
- }
- }
-
- /**
- * @return The value associated with the given key.
- */
- public String getKey(final String cfName, final String key) {
- return getKey(cfName, key, "value");
- }
-
- /**
- * @return The value associated with the given key, column pair.
- */
- public String getKey(final String cfName, final String key, final String column) {
- final ColumnList<String> row = getRow(cfName, key);
-
- if (row != null) {
- final Column rowColumn = row.getColumnByName(column);
- if (rowColumn != null) {
- return rowColumn.getStringValue();
- }
- }
-
- return null;
- }
-
- /**
- * Assign value to key.
- */
- public void putKey(final String cfName, final String key, final String value) {
- putKey(cfName, key, "value", value);
- }
-
- /**
- * Assign value to the key, column pair.
- */
- public void putKey(final String cfName, final String key,
- final String column, final String value) {
-
- ColumnFamily<String, String> cf = new ColumnFamily(cfName,
- StringSerializer.get(),
- StringSerializer.get());
-
- MutationBatch m = mKeyspace.prepareMutationBatch();
- m.withRow(cf, key).putColumn(column, value);
-
- try {
- m.execute();
- } catch (ConnectionException e) {
- cLog.error("putKey failed due to Connection Exception", e);
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Remove a key, column pair.
- */
- public void deleteKey(final String cfName, final String key, final String column) {
- ColumnFamily<String, String> cf = new ColumnFamily(cfName,
- StringSerializer.get(),
- StringSerializer.get());
-
- try {
- ColumnMutation m = mKeyspace.prepareColumnMutation(cf, key, column);
- m.deleteColumn().execute();
- } catch (ConnectionException e) {
- cLog.error("deleteKey failed due to Connection Exception", e);
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Remove a row
- */
- public void deleteRow(final String cfName, final String key) {
- ColumnFamily<String, String> cf = new ColumnFamily(cfName,
- StringSerializer.get(),
- StringSerializer.get());
-
- try {
- MutationBatch batch = mKeyspace.prepareMutationBatch();
- ColumnListMutation<String> cfm = batch.withRow(cf, key).delete();
- batch.execute();
-
- } catch (ConnectionException e) {
- cLog.error("deleteRow failed due to Connection Exception", e);
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/db/CassandraKey.java b/src/com/p4square/grow/backend/db/CassandraKey.java
deleted file mode 100644
index 853fe96..0000000
--- a/src/com/p4square/grow/backend/db/CassandraKey.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.db;
-
-/**
- * CassandraKey represents a Cassandra key / column pair.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class CassandraKey {
- private final String mColumnFamily;
- private final String mId;
- private final String mColumn;
-
- public CassandraKey(String columnFamily, String id, String column) {
- mColumnFamily = columnFamily;
- mId = id;
- mColumn = column;
- }
-
- public String getColumnFamily() {
- return mColumnFamily;
- }
-
- public String getId() {
- return mId;
- }
-
- public String getColumn() {
- return mColumn;
- }
-}
diff --git a/src/com/p4square/grow/backend/db/CassandraProviderImpl.java b/src/com/p4square/grow/backend/db/CassandraProviderImpl.java
deleted file mode 100644
index da5a9f2..0000000
--- a/src/com/p4square/grow/backend/db/CassandraProviderImpl.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.db;
-
-import java.io.IOException;
-
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- * Provider implementation backed by a Cassandra ColumnFamily.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class CassandraProviderImpl<V> extends JsonEncodedProvider<V> implements Provider<CassandraKey, V> {
- private final CassandraDatabase mDb;
-
- public CassandraProviderImpl(CassandraDatabase db, Class<V> clazz) {
- super(clazz);
-
- mDb = db;
- }
-
- @Override
- public V get(CassandraKey key) throws IOException {
- String blob = mDb.getKey(key.getColumnFamily(), key.getId(), key.getColumn());
- return decode(blob);
- }
-
- @Override
- public void put(CassandraKey key, V obj) throws IOException {
- String blob = encode(obj);
- mDb.putKey(key.getColumnFamily(), key.getId(), key.getColumn(), blob);
- }
-}
diff --git a/src/com/p4square/grow/backend/db/CassandraTrainingRecordProvider.java b/src/com/p4square/grow/backend/db/CassandraTrainingRecordProvider.java
deleted file mode 100644
index 4face52..0000000
--- a/src/com/p4square/grow/backend/db/CassandraTrainingRecordProvider.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.db;
-
-import java.io.IOException;
-
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.model.TrainingRecord;
-
-import com.p4square.grow.provider.JsonEncodedProvider;
-import com.p4square.grow.provider.Provider;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class CassandraTrainingRecordProvider implements Provider<String, TrainingRecord> {
- private static final CassandraKey DEFAULT_PLAYLIST_KEY = new CassandraKey("strings", "defaultPlaylist", "value");
-
- private static final String COLUMN_FAMILY = "training";
- private static final String PLAYLIST_KEY = "playlist";
- private static final String LAST_VIDEO_KEY = "lastVideo";
-
- private final CassandraDatabase mDb;
- private final Provider<CassandraKey, Playlist> mPlaylistProvider;
-
- public CassandraTrainingRecordProvider(CassandraDatabase db) {
- mDb = db;
- mPlaylistProvider = new CassandraProviderImpl<>(db, Playlist.class);
- }
-
- @Override
- public TrainingRecord get(String userid) throws IOException {
- Playlist playlist = mPlaylistProvider.get(new CassandraKey(COLUMN_FAMILY, userid, PLAYLIST_KEY));
-
- if (playlist == null) {
- // We consider no playlist to mean no record whatsoever.
- return null;
- }
-
- TrainingRecord r = new TrainingRecord();
- r.setPlaylist(playlist);
- r.setLastVideo(mDb.getKey(COLUMN_FAMILY, userid, LAST_VIDEO_KEY));
-
- return r;
- }
-
- @Override
- public void put(String userid, TrainingRecord record) throws IOException {
- String lastVideo = record.getLastVideo();
- Playlist playlist = record.getPlaylist();
-
- mDb.putKey(COLUMN_FAMILY, userid, LAST_VIDEO_KEY, lastVideo);
- mPlaylistProvider.put(new CassandraKey(COLUMN_FAMILY, userid, PLAYLIST_KEY), playlist);
- }
-
- /**
- * @return the default playlist stored in the database.
- */
- public Playlist getDefaultPlaylist() throws IOException {
- Playlist playlist = mPlaylistProvider.get(DEFAULT_PLAYLIST_KEY);
-
- if (playlist == null) {
- playlist = new Playlist();
- }
-
- return playlist;
- }
-}
diff --git a/src/com/p4square/grow/backend/dynamo/DbTool.java b/src/com/p4square/grow/backend/dynamo/DbTool.java
deleted file mode 100644
index 374fa83..0000000
--- a/src/com/p4square/grow/backend/dynamo/DbTool.java
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend.dynamo;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-
-import com.p4square.grow.backend.dynamo.DynamoDatabase;
-import com.p4square.grow.backend.dynamo.DynamoKey;
-import com.p4square.grow.config.Config;
-import com.p4square.grow.model.UserRecord;
-import com.p4square.grow.provider.Provider;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class DbTool {
- private static final FilenameFilter JSON_FILTER = new JsonFilter();
-
- private static Config mConfig;
- private static DynamoDatabase mDatabase;
-
- public static void usage() {
- System.out.println("java com.p4square.grow.backend.dynamo.DbTool <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 tables");
- System.out.println("\t--create <table> <reads> <writes> Create a table");
- System.out.println("\t--update <table> <reads> <writes> Update table throughput");
- System.out.println("\t--drop <table> Delete a table");
- System.out.println("\t--get <table> <key> <attribute> Get a value");
- System.out.println("\t--put <table> <key> <attribute> <value> Put a value");
- System.out.println("\t--delete <table> <key> <attribute> Delete a value");
- System.out.println("\t--scan <table> List all rows");
- System.out.println("\t--scanf <table> <attribute> List all rows");
- System.out.println();
- System.out.println("Bootstrap Commands:");
- System.out.println("\t--bootstrap <data> Create all tables and import all data");
- System.out.println("\t--loadStrings <data> Load all videos and questions");
- System.out.println("\t--destroy Drop all tables");
- System.out.println("\t--addadmin <user> <pass> Add a backend account");
- System.out.println("\t--import <table> <file> Backfill a table");
- }
-
- public static void main(String... args) {
- if (args.length == 0) {
- usage();
- System.exit(1);
- }
-
- mConfig = new Config();
-
- try {
- mConfig.updateConfig(DbTool.class.getResourceAsStream("/grow.properties"));
-
- int offset = 0;
- while (offset < args.length) {
- if ("--domain".equals(args[offset])) {
- mConfig.setDomain(args[offset + 1]);
- mDatabase = null;
- offset += 2;
-
- } else if ("--dev".equals(args[offset])) {
- mConfig.setDomain("dev");
- mDatabase = null;
- offset += 1;
-
- } else if ("--config".equals(args[offset])) {
- mConfig.updateConfig(args[offset + 1]);
- mDatabase = null;
- offset += 2;
-
- } else if ("--list".equals(args[offset])) {
- //offset = list(args, ++offset);
-
- } else if ("--create".equals(args[offset])) {
- offset = create(args, ++offset);
-
- } else if ("--update".equals(args[offset])) {
- offset = update(args, ++offset);
-
- } else if ("--drop".equals(args[offset])) {
- offset = drop(args, ++offset);
-
- } else if ("--get".equals(args[offset])) {
- offset = get(args, ++offset);
-
- } else if ("--put".equals(args[offset])) {
- offset = put(args, ++offset);
-
- } else if ("--delete".equals(args[offset])) {
- offset = delete(args, ++offset);
-
- } else if ("--scan".equals(args[offset])) {
- offset = scan(args, ++offset);
-
- } else if ("--scanf".equals(args[offset])) {
- offset = scanf(args, ++offset);
-
- /* Bootstrap Commands */
- } else if ("--bootstrap".equals(args[offset])) {
- if ("dev".equals(mConfig.getDomain())) {
- offset = bootstrapDevTables(args, ++offset);
- } else {
- offset = bootstrapTables(args, ++offset);
- }
- offset = loadStrings(args, offset);
-
- } else if ("--loadStrings".equals(args[offset])) {
- offset = loadStrings(args, ++offset);
-
- } else if ("--destroy".equals(args[offset])) {
- offset = destroy(args, ++offset);
-
- } else if ("--addadmin".equals(args[offset])) {
- offset = addAdmin(args, ++offset);
-
- } else if ("--import".equals(args[offset])) {
- offset = importTable(args, ++offset);
-
- } else {
- throw new IllegalArgumentException("Unknown command " + args[offset]);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(2);
- }
- }
-
- private static DynamoDatabase getDatabase() {
- if (mDatabase == null) {
- mDatabase = new DynamoDatabase(mConfig);
- }
-
- return mDatabase;
- }
-
- private static int create(String[] args, int offset) {
- String name = args[offset++];
- long reads = Long.parseLong(args[offset++]);
- long writes = Long.parseLong(args[offset++]);
-
- DynamoDatabase db = getDatabase();
-
- db.createTable(name, reads, writes);
-
- return offset;
- }
-
- private static int update(String[] args, int offset) {
- String name = args[offset++];
- long reads = Long.parseLong(args[offset++]);
- long writes = Long.parseLong(args[offset++]);
-
- DynamoDatabase db = getDatabase();
-
- db.updateTable(name, reads, writes);
-
- return offset;
- }
-
- private static int drop(String[] args, int offset) {
- String name = args[offset++];
-
- DynamoDatabase db = getDatabase();
-
- db.deleteTable(name);
-
- return offset;
- }
-
- private static int get(String[] args, int offset) {
- String table = args[offset++];
- String key = args[offset++];
- String attribute = args[offset++];
-
- DynamoDatabase db = getDatabase();
-
- String value = db.getAttribute(DynamoKey.newAttributeKey(table, key, attribute));
-
- if (value == null) {
- value = "<null>";
- }
-
- System.out.printf("%s %s:%s\n%s\n\n", table, key, attribute, value);
-
- return offset;
- }
-
- private static int put(String[] args, int offset) {
- String table = args[offset++];
- String key = args[offset++];
- String attribute = args[offset++];
- String value = args[offset++];
-
- DynamoDatabase db = getDatabase();
-
- db.putAttribute(DynamoKey.newAttributeKey(table, key, attribute), value);
-
- return offset;
- }
-
- private static int delete(String[] args, int offset) {
- String table = args[offset++];
- String key = args[offset++];
- String attribute = args[offset++];
-
- DynamoDatabase db = getDatabase();
-
- db.deleteAttribute(DynamoKey.newAttributeKey(table, key, attribute));
-
- System.out.printf("Deleted %s %s:%s\n\n", table, key, attribute);
-
- return offset;
- }
-
- private static int scan(String[] args, int offset) {
- String table = args[offset++];
-
- DynamoKey key = DynamoKey.newKey(table, null);
-
- doScan(key);
-
- return offset;
- }
-
- private static int scanf(String[] args, int offset) {
- String table = args[offset++];
- String attribute = args[offset++];
-
- DynamoKey key = DynamoKey.newAttributeKey(table, null, attribute);
-
- doScan(key);
-
- return offset;
- }
-
- private static void doScan(DynamoKey key) {
- DynamoDatabase db = getDatabase();
-
- String attributeFilter = key.getAttribute();
-
- while (key != null) {
- Map<DynamoKey, Map<String, String>> result = db.getAll(key);
-
- key = null; // If there are no results, exit
-
- for (Map.Entry<DynamoKey, Map<String, String>> entry : result.entrySet()) {
- key = entry.getKey(); // Save the last key
-
- for (Map.Entry<String, String> attribute : entry.getValue().entrySet()) {
- if (attributeFilter == null || attributeFilter.equals(attribute.getKey())) {
- String keyString = key.getHashKey();
- if (key.getRangeKey() != null) {
- keyString += "(" + key.getRangeKey() + ")";
- }
- System.out.printf("%s %s:%s\n%s\n\n",
- key.getTable(), keyString, attribute.getKey(),
- attribute.getValue());
- }
- }
- }
- }
- }
-
-
- private static int bootstrapTables(String[] args, int offset) {
- DynamoDatabase db = getDatabase();
-
- db.createTable("strings", 5, 1);
- db.createTable("accounts", 5, 1);
- db.createTable("assessments", 5, 5);
- db.createTable("training", 5, 5);
- db.createTable("feedthreads", 5, 1);
- db.createTable("feedmessages", 5, 1);
-
- return offset;
- }
-
- private static int bootstrapDevTables(String[] args, int offset) {
- DynamoDatabase db = getDatabase();
-
- db.createTable("strings", 1, 1);
- db.createTable("accounts", 1, 1);
- db.createTable("assessments", 1, 1);
- db.createTable("training", 1, 1);
- db.createTable("feedthreads", 1, 1);
- db.createTable("feedmessages", 1, 1);
-
- return offset;
- }
-
- private static int loadStrings(String[] args, int offset) throws IOException {
- String data = args[offset++];
- File baseDir = new File(data);
-
- DynamoDatabase db = getDatabase();
-
- insertQuestions(baseDir);
- insertVideos(baseDir);
- insertDefaultPlaylist(baseDir);
-
- return offset;
- }
-
- private static int destroy(String[] args, int offset) {
- DynamoDatabase db = getDatabase();
-
- final String[] tables = { "strings",
- "accounts",
- "assessments",
- "training",
- "feedthreads",
- "feedmessages"
- };
-
- for (String table : tables) {
- try {
- db.deleteTable(table);
- } catch (Exception e) {
- System.err.println("Deleting " + table + ": " + e.getMessage());
- }
- }
-
- return offset;
- }
-
- private static int addAdmin(String[] args, int offset) throws IOException {
- String user = args[offset++];
- String pass = args[offset++];
-
- DynamoDatabase db = getDatabase();
-
- UserRecord record = new UserRecord();
- record.setId(user);
- record.setBackendPassword(pass);
-
- Provider<DynamoKey, UserRecord> provider = new DynamoProviderImpl(db, UserRecord.class);
- provider.put(DynamoKey.newAttributeKey("accounts", user, "value"), record);
-
- return offset;
- }
-
- private static int importTable(String[] args, int offset) throws IOException {
- String table = args[offset++];
- String filename = args[offset++];
-
- DynamoDatabase db = getDatabase();
-
- List<String> lines = Files.readAllLines(new File(filename).toPath(),
- StandardCharsets.UTF_8);
-
- int count = 0;
-
- String key = null;
- Map<String, String> attributes = new HashMap<>();
- for (String line : lines) {
- if (line.length() == 0) {
- if (attributes.size() > 0) {
- db.putKey(DynamoKey.newKey(table, key), attributes);
- count++;
-
- if (count % 50 == 0) {
- System.out.printf("Imported %d records into %s...\n", count, table);
- }
- }
- key = null;
- attributes = new HashMap<>();
- continue;
- }
-
- if (key == null) {
- key = line;
- continue;
- }
-
- int space = line.indexOf(' ');
- String attribute = line.substring(0, space);
- String value = line.substring(space + 1);
-
- attributes.put(attribute, value);
- }
-
- // Finish up the remaining attributes.
- if (key != null && attributes.size() > 0) {
- db.putKey(DynamoKey.newKey(table, key), attributes);
- count++;
- }
-
- System.out.printf("Imported %d records into %s.\n", count, table);
-
- return offset;
- }
-
- private static void insertQuestions(File baseDir) throws IOException {
- DynamoDatabase db = getDatabase();
- File questions = new File(baseDir, "questions");
-
- File[] files = questions.listFiles(JSON_FILTER);
- Arrays.sort(files);
-
- for (File file : files) {
- String filename = file.getName();
- String questionId = filename.substring(0, filename.lastIndexOf('.'));
-
- byte[] encoded = Files.readAllBytes(file.toPath());
- String value = new String(encoded, StandardCharsets.UTF_8);
- db.putAttribute(DynamoKey.newAttributeKey("strings",
- "/questions/" + questionId, "value"), value);
- System.out.println("Inserted /questions/" + questionId);
- }
-
- String filename = files[0].getName();
- String first = filename.substring(0, filename.lastIndexOf('.'));
- int count = files.length;
- String summary = "{\"first\": \"" + first + "\", \"count\": " + count + "}";
- db.putAttribute(DynamoKey.newAttributeKey("strings", "/questions", "value"), summary);
- System.out.println("Inserted /questions");
- }
-
- private static void insertVideos(File baseDir) throws IOException {
- DynamoDatabase db = getDatabase();
- File videos = new File(baseDir, "videos");
-
- for (File topic : videos.listFiles()) {
- if (!topic.isDirectory()) {
- continue;
- }
-
- String topicName = topic.getName();
-
- Map<String, String> attributes = new HashMap<>();
- File[] files = topic.listFiles(JSON_FILTER);
- for (File file : files) {
- String filename = file.getName();
- String videoId = filename.substring(0, filename.lastIndexOf('.'));
-
- byte[] encoded = Files.readAllBytes(file.toPath());
- String value = new String(encoded, StandardCharsets.UTF_8);
-
- attributes.put(videoId, value);
- System.out.println("Found /training/" + topicName + ":" + videoId);
- }
-
- db.putKey(DynamoKey.newKey("strings",
- "/training/" + topicName), attributes);
- System.out.println("Inserted /training/" + topicName);
- }
- }
-
- private static void insertDefaultPlaylist(File baseDir) throws IOException {
- DynamoDatabase db = getDatabase();
- File file = new File(baseDir, "videos/playlist.json");
-
- byte[] encoded = Files.readAllBytes(file.toPath());
- String value = new String(encoded, StandardCharsets.UTF_8);
- db.putAttribute(DynamoKey.newAttributeKey("strings",
- "/training/defaultplaylist", "value"), value);
- System.out.println("Inserted /training/defaultplaylist");
- }
-
- private static class JsonFilter implements FilenameFilter {
- @Override
- public boolean accept(File dir, String name) {
- return name.endsWith(".json");
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/dynamo/DynamoCollectionProviderImpl.java b/src/com/p4square/grow/backend/dynamo/DynamoCollectionProviderImpl.java
deleted file mode 100644
index b53e9f7..0000000
--- a/src/com/p4square/grow/backend/dynamo/DynamoCollectionProviderImpl.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend.dynamo;
-
-import java.io.IOException;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class DynamoCollectionProviderImpl<V> implements CollectionProvider<String, String, V> {
- private final DynamoDatabase mDb;
- private final String mTable;
- private final Class<V> mClazz;
-
- public DynamoCollectionProviderImpl(DynamoDatabase db, String table, Class<V> clazz) {
- mDb = db;
- mTable = table;
- mClazz = clazz;
- }
-
- @Override
- public V get(String collection, String key) throws IOException {
- String blob = mDb.getAttribute(DynamoKey.newAttributeKey(mTable, collection, key));
- return decode(blob);
- }
-
- @Override
- public Map<String, V> query(String collection) throws IOException {
- return query(collection, -1);
- }
-
- @Override
- public Map<String, V> query(String collection, int limit) throws IOException {
- Map<String, V> result = new LinkedHashMap<>();
-
- Map<String, String> row = mDb.getKey(DynamoKey.newKey(mTable, collection));
- if (row.size() > 0) {
- int count = 0;
- for (Map.Entry<String, String> c : row.entrySet()) {
- if (limit >= 0 && ++count > limit) {
- break; // Limit reached.
- }
-
- String key = c.getKey();
- String blob = c.getValue();
- V obj = decode(blob);
-
- result.put(key, obj);
- }
- }
-
- return Collections.unmodifiableMap(result);
- }
-
- @Override
- public void put(String collection, String key, V obj) throws IOException {
- if (obj == null) {
- mDb.deleteAttribute(DynamoKey.newAttributeKey(mTable, collection, key));
- } else {
- String blob = encode(obj);
- mDb.putAttribute(DynamoKey.newAttributeKey(mTable, collection, key), blob);
- }
- }
-
- /**
- * Encode the object as JSON.
- *
- * @param obj The object to encode.
- * @return The JSON encoding of obj.
- * @throws IOException if the object cannot be encoded.
- */
- protected String encode(V obj) throws IOException {
- if (mClazz == String.class) {
- return (String) obj;
- } else {
- return JsonEncodedProvider.MAPPER.writeValueAsString(obj);
- }
- }
-
- /**
- * Decode the JSON string as an object.
- *
- * @param blob The JSON data to decode.
- * @return The decoded object or null if blob is null.
- * @throws IOException If an object cannot be decoded.
- */
- protected V decode(String blob) throws IOException {
- if (blob == null) {
- return null;
- }
-
- if (mClazz == String.class) {
- return (V) blob;
- }
-
- V obj = JsonEncodedProvider.MAPPER.readValue(blob, mClazz);
- return obj;
- }
-}
diff --git a/src/com/p4square/grow/backend/dynamo/DynamoDatabase.java b/src/com/p4square/grow/backend/dynamo/DynamoDatabase.java
deleted file mode 100644
index 68a165d..0000000
--- a/src/com/p4square/grow/backend/dynamo/DynamoDatabase.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend.dynamo;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import com.amazonaws.auth.AWSCredentials;
-import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
-import com.amazonaws.regions.Region;
-import com.amazonaws.regions.Regions;
-import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
-import com.amazonaws.services.dynamodbv2.model.AttributeAction;
-import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
-import com.amazonaws.services.dynamodbv2.model.AttributeValue;
-import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
-import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
-import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
-import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest;
-import com.amazonaws.services.dynamodbv2.model.DeleteItemResult;
-import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest;
-import com.amazonaws.services.dynamodbv2.model.DeleteTableResult;
-import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
-import com.amazonaws.services.dynamodbv2.model.GetItemResult;
-import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
-import com.amazonaws.services.dynamodbv2.model.KeyType;
-import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
-import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
-import com.amazonaws.services.dynamodbv2.model.PutItemResult;
-import com.amazonaws.services.dynamodbv2.model.ScanRequest;
-import com.amazonaws.services.dynamodbv2.model.ScanResult;
-import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest;
-import com.amazonaws.services.dynamodbv2.model.UpdateItemResult;
-import com.amazonaws.services.dynamodbv2.model.UpdateTableRequest;
-import com.amazonaws.services.dynamodbv2.model.UpdateTableResult;
-
-import com.p4square.grow.config.Config;
-
-/**
- * A wrapper around the Dynamo API.
- */
-public class DynamoDatabase {
- private final AmazonDynamoDBClient mClient;
- private final String mTablePrefix;
-
- public DynamoDatabase(final Config config) {
- AWSCredentials creds;
-
- String awsAccessKey = config.getString("awsAccessKey");
- if (awsAccessKey != null) {
- creds = new AWSCredentials() {
- @Override
- public String getAWSAccessKeyId() {
- return config.getString("awsAccessKey");
- }
- @Override
- public String getAWSSecretKey() {
- return config.getString("awsSecretKey");
- }
- };
- } else {
- creds = new DefaultAWSCredentialsProviderChain().getCredentials();
- }
-
- mClient = new AmazonDynamoDBClient(creds);
-
- String endpoint = config.getString("dynamoEndpoint");
- if (endpoint != null) {
- mClient.setEndpoint(endpoint);
- }
-
- String region = config.getString("awsRegion");
- if (region != null) {
- mClient.setRegion(Region.getRegion(Regions.fromName(region)));
- }
-
- mTablePrefix = config.getString("dynamoTablePrefix", "");
- }
-
- public void createTable(String name, long reads, long writes) {
- ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<>();
- attributeDefinitions.add(new AttributeDefinition()
- .withAttributeName("id")
- .withAttributeType("S"));
-
- ArrayList<KeySchemaElement> ks = new ArrayList<>();
- ks.add(new KeySchemaElement().withAttributeName("id").withKeyType(KeyType.HASH));
-
- ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput()
- .withReadCapacityUnits(reads)
- .withWriteCapacityUnits(writes);
-
- CreateTableRequest request = new CreateTableRequest()
- .withTableName(mTablePrefix + name)
- .withAttributeDefinitions(attributeDefinitions)
- .withKeySchema(ks)
- .withProvisionedThroughput(provisionedThroughput);
-
- CreateTableResult result = mClient.createTable(request);
- }
-
- public void updateTable(String name, long reads, long writes) {
- ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput()
- .withReadCapacityUnits(reads)
- .withWriteCapacityUnits(writes);
-
- UpdateTableRequest request = new UpdateTableRequest()
- .withTableName(mTablePrefix + name)
- .withProvisionedThroughput(provisionedThroughput);
-
- UpdateTableResult result = mClient.updateTable(request);
- }
-
- public void deleteTable(String name) {
- DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
- .withTableName(mTablePrefix + name);
-
- DeleteTableResult result = mClient.deleteTable(deleteTableRequest);
- }
-
- /**
- * Get all rows from a table.
- *
- * The key parameter must specify a table. If hash/range key is specified,
- * the scan will begin after that key.
- *
- * @param key Previous key to start with.
- * @return An ordered map of all results.
- */
- public Map<DynamoKey, Map<String, String>> getAll(final DynamoKey key) {
- ScanRequest scanRequest = new ScanRequest().withTableName(mTablePrefix + key.getTable());
-
- if (key.getHashKey() != null) {
- scanRequest.setExclusiveStartKey(generateKey(key));
- }
-
- ScanResult scanResult = mClient.scan(scanRequest);
-
- Map<DynamoKey, Map<String, String>> result = new LinkedHashMap<>();
- for (Map<String, AttributeValue> map : scanResult.getItems()) {
- String id = null;
- String range = null;
- Map<String, String> row = new LinkedHashMap<>();
- for (Map.Entry<String, AttributeValue> entry : map.entrySet()) {
- if ("id".equals(entry.getKey())) {
- id = entry.getValue().getS();
- } else if ("range".equals(entry.getKey())) {
- range = entry.getValue().getS();
- } else {
- row.put(entry.getKey(), entry.getValue().getS());
- }
- }
- result.put(DynamoKey.newRangeKey(key.getTable(), id, range), row);
- }
-
- return result;
- }
-
- public Map<String, String> getKey(final DynamoKey key) {
- GetItemRequest getItemRequest = new GetItemRequest()
- .withTableName(mTablePrefix + key.getTable())
- .withKey(generateKey(key));
-
- GetItemResult getItemResult = mClient.getItem(getItemRequest);
- Map<String, AttributeValue> map = getItemResult.getItem();
-
- Map<String, String> result = new LinkedHashMap<>();
- if (map != null) {
- for (Map.Entry<String, AttributeValue> entry : map.entrySet()) {
- if (!"id".equals(entry.getKey())) {
- result.put(entry.getKey(), entry.getValue().getS());
- }
- }
- }
-
- return result;
- }
-
- public String getAttribute(final DynamoKey key) {
- checkAttributeKey(key);
-
- GetItemRequest getItemRequest = new GetItemRequest()
- .withTableName(mTablePrefix + key.getTable())
- .withKey(generateKey(key))
- .withAttributesToGet(key.getAttribute());
-
- GetItemResult result = mClient.getItem(getItemRequest);
- Map<String, AttributeValue> map = result.getItem();
-
- if (map == null) {
- return null;
- }
-
- AttributeValue value = map.get(key.getAttribute());
- if (value != null) {
- return value.getS();
-
- } else {
- return null;
- }
- }
-
- /**
- * Set all attributes for the given key.
- *
- * @param key The key.
- * @param values Map of attributes to values.
- */
- public void putKey(final DynamoKey key, final Map<String, String> values) {
- Map<String, AttributeValue> item = new HashMap<>();
- for (Map.Entry<String, String> entry : values.entrySet()) {
- item.put(entry.getKey(), new AttributeValue().withS(entry.getValue()));
- }
-
- // Set the Key
- item.putAll(generateKey(key));
-
- PutItemRequest putItemRequest = new PutItemRequest()
- .withTableName(mTablePrefix + key.getTable())
- .withItem(item);
-
- PutItemResult result = mClient.putItem(putItemRequest);
- }
-
- /**
- * Set the particular attributes of the given key.
- *
- * @param key The key.
- * @param value The new value.
- */
- public void putAttribute(final DynamoKey key, final String value) {
- checkAttributeKey(key);
-
- Map<String, AttributeValueUpdate> updateItem = new HashMap<>();
- updateItem.put(key.getAttribute(),
- new AttributeValueUpdate()
- .withAction(AttributeAction.PUT)
- .withValue(new AttributeValue().withS(value)));
-
- UpdateItemRequest updateItemRequest = new UpdateItemRequest()
- .withTableName(mTablePrefix + key.getTable())
- .withKey(generateKey(key))
- .withAttributeUpdates(updateItem);
- // TODO: Check conditions.
-
- UpdateItemResult result = mClient.updateItem(updateItemRequest);
- }
-
- /**
- * Delete the given key.
- *
- * @param key The key.
- */
- public void deleteKey(final DynamoKey key) {
- DeleteItemRequest deleteItemRequest = new DeleteItemRequest()
- .withTableName(mTablePrefix + key.getTable())
- .withKey(generateKey(key));
-
- DeleteItemResult result = mClient.deleteItem(deleteItemRequest);
- }
-
- /**
- * Delete an attribute from the given key.
- *
- * @param key The key.
- */
- public void deleteAttribute(final DynamoKey key) {
- checkAttributeKey(key);
-
- Map<String, AttributeValueUpdate> updateItem = new HashMap<>();
- updateItem.put(key.getAttribute(),
- new AttributeValueUpdate().withAction(AttributeAction.DELETE));
-
- UpdateItemRequest updateItemRequest = new UpdateItemRequest()
- .withTableName(mTablePrefix + key.getTable())
- .withKey(generateKey(key))
- .withAttributeUpdates(updateItem);
-
- UpdateItemResult result = mClient.updateItem(updateItemRequest);
- }
-
- /**
- * Generate a DynamoDB Key Map from the DynamoKey.
- */
- private Map<String, AttributeValue> generateKey(final DynamoKey key) {
- HashMap<String, AttributeValue> keyMap = new HashMap<>();
- keyMap.put("id", new AttributeValue().withS(key.getHashKey()));
-
- String range = key.getRangeKey();
- if (range != null) {
- keyMap.put("range", new AttributeValue().withS(range));
- }
-
- return keyMap;
- }
-
- private void checkAttributeKey(DynamoKey key) {
- if (null == key.getAttribute()) {
- throw new IllegalArgumentException("Attribute must be non-null");
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/dynamo/DynamoKey.java b/src/com/p4square/grow/backend/dynamo/DynamoKey.java
deleted file mode 100644
index 5cdbacd..0000000
--- a/src/com/p4square/grow/backend/dynamo/DynamoKey.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.backend.dynamo;
-
-/**
- * DynamoKey represents a table, hash key, and range key tupl.
- */
-public class DynamoKey {
- private final String mTable;
- private final String mHashKey;
- private final String mRangeKey;
- private final String mAttribute;
-
- public static DynamoKey newKey(final String table, final String hashKey) {
- return new DynamoKey(table, hashKey, null, null);
- }
-
- public static DynamoKey newRangeKey(final String table, final String hashKey,
- final String rangeKey) {
-
- return new DynamoKey(table, hashKey, rangeKey, null);
- }
-
- public static DynamoKey newAttributeKey(final String table, final String hashKey,
- final String attribute) {
-
- return new DynamoKey(table, hashKey, null, attribute);
- }
-
- public DynamoKey(final String table, final String hashKey, final String rangeKey,
- final String attribute) {
-
- mTable = table;
- mHashKey = hashKey;
- mRangeKey = rangeKey;
- mAttribute = attribute;
- }
-
- public String getTable() {
- return mTable;
- }
-
- public String getHashKey() {
- return mHashKey;
- }
-
- public String getRangeKey() {
- return mRangeKey;
- }
-
- public String getAttribute() {
- return mAttribute;
- }
-}
diff --git a/src/com/p4square/grow/backend/dynamo/DynamoProviderImpl.java b/src/com/p4square/grow/backend/dynamo/DynamoProviderImpl.java
deleted file mode 100644
index 93a535f..0000000
--- a/src/com/p4square/grow/backend/dynamo/DynamoProviderImpl.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.dynamo;
-
-import java.io.IOException;
-
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- * Provider implementation backed by a DynamoDB Table.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class DynamoProviderImpl<V> extends JsonEncodedProvider<V> implements Provider<DynamoKey, V> {
- private final DynamoDatabase mDb;
-
- public DynamoProviderImpl(DynamoDatabase db, Class<V> clazz) {
- super(clazz);
-
- mDb = db;
- }
-
- @Override
- public V get(DynamoKey key) throws IOException {
- String blob = mDb.getAttribute(key);
- return decode(blob);
- }
-
- @Override
- public void put(DynamoKey key, V obj) throws IOException {
- String blob = encode(obj);
- mDb.putAttribute(key, blob);
- }
-}
diff --git a/src/com/p4square/grow/backend/feed/FeedDataProvider.java b/src/com/p4square/grow/backend/feed/FeedDataProvider.java
deleted file mode 100644
index 6f090c0..0000000
--- a/src/com/p4square/grow/backend/feed/FeedDataProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.feed;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
-import com.p4square.grow.model.MessageThread;
-import com.p4square.grow.model.Message;
-import com.p4square.grow.provider.CollectionProvider;
-
-/**
- * Implementing this interface indicates you can provide a data source for the Feed.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface FeedDataProvider {
- public static final Collection<String> TOPICS = Collections.unmodifiableCollection(
- Arrays.asList(new String[] { "seeker", "believer", "disciple", "teacher", "leader" }));
-
- /**
- * @return a CollectionProvider of Threads.
- */
- CollectionProvider<String, String, MessageThread> getThreadProvider();
-
- /**
- * @return a CollectionProvider of Messages.
- */
- CollectionProvider<String, String, Message> getMessageProvider();
-}
diff --git a/src/com/p4square/grow/backend/feed/ThreadResource.java b/src/com/p4square/grow/backend/feed/ThreadResource.java
deleted file mode 100644
index e8f46c2..0000000
--- a/src/com/p4square/grow/backend/feed/ThreadResource.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.feed;
-
-import java.io.IOException;
-
-import java.util.Date;
-import java.util.Map;
-
-import org.restlet.data.Status;
-import org.restlet.resource.ServerResource;
-import org.restlet.representation.Representation;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.model.Message;
-
-/**
- * ThreadResource manages the messages that make up a thread.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class ThreadResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(ThreadResource.class);
-
- private FeedDataProvider mBackend;
- private String mTopic;
- private String mThreadId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mBackend = (FeedDataProvider) getApplication();
- mTopic = getAttribute("topic");
- mThreadId = getAttribute("thread");
- }
-
- /**
- * GET a list of messages in a thread.
- */
- @Override
- protected Representation get() {
- // If the topic or threadId are missing, return a 404.
- if (mTopic == null || mTopic.length() == 0 ||
- mThreadId == null || mThreadId.length() == 0) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- // TODO: Support limit query parameter.
-
- try {
- String collectionKey = mTopic + "/" + mThreadId;
- Map<String, Message> messages = mBackend.getMessageProvider().query(collectionKey);
- return new JacksonRepresentation(messages.values());
-
- } catch (IOException e) {
- LOG.error("Unexpected exception: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-
- /**
- * POST a new message to the thread.
- */
- @Override
- protected Representation post(Representation entity) {
- // If the topic and thread are not provided, respond with not allowed.
- // TODO: Check if the thread exists.
- if (mTopic == null || !mBackend.TOPICS.contains(mTopic) ||
- mThreadId == null || mThreadId.length() == 0) {
- setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
- return null;
- }
-
- try {
- JacksonRepresentation<Message> jsonRep = new JacksonRepresentation<Message>(entity, Message.class);
- Message message = jsonRep.getObject();
-
- // Force the thread id and message to be what we expect.
- message.setThreadId(mThreadId);
- message.setId(Message.generateId());
-
- if (message.getCreated() == null) {
- message.setCreated(new Date());
- }
-
- String collectionKey = mTopic + "/" + mThreadId;
- mBackend.getMessageProvider().put(collectionKey, message.getId(), message);
-
- setLocationRef(mThreadId + "/" + message.getId());
- return new JacksonRepresentation(message);
-
- } catch (IOException e) {
- LOG.error("Unexpected exception: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/feed/TopicResource.java b/src/com/p4square/grow/backend/feed/TopicResource.java
deleted file mode 100644
index 24b6a92..0000000
--- a/src/com/p4square/grow/backend/feed/TopicResource.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.feed;
-
-import java.io.IOException;
-
-import java.util.Date;
-import java.util.Map;
-
-import org.restlet.data.Status;
-import org.restlet.resource.ServerResource;
-import org.restlet.representation.Representation;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.model.Message;
-import com.p4square.grow.model.MessageThread;
-
-/**
- * TopicResource manages the threads contained in a topic.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class TopicResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(TopicResource.class);
-
- private FeedDataProvider mBackend;
- private String mTopic;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mBackend = (FeedDataProvider) getApplication();
- mTopic = getAttribute("topic");
- }
-
- /**
- * GET a list of threads in the topic.
- */
- @Override
- protected Representation get() {
- // If no topic is provided, return a list of topics.
- if (mTopic == null || mTopic.length() == 0) {
- return new JacksonRepresentation(FeedDataProvider.TOPICS);
- }
-
- // Parse limit query parameter.
- int limit = -1;
- String limitString = getQueryValue("limit");
- if (limitString != null) {
- try {
- limit = Integer.parseInt(limitString);
- } catch (NumberFormatException e) {
- setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
- return null;
- }
- }
-
- try {
- Map<String, MessageThread> threads = mBackend.getThreadProvider().query(mTopic, limit);
- return new JacksonRepresentation(threads.values());
-
- } catch (IOException e) {
- LOG.error("Unexpected exception: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-
- /**
- * POST a new thread to the topic.
- */
- @Override
- protected Representation post(Representation entity) {
- // If no topic is provided, respond with not allowed.
- if (mTopic == null || !mBackend.TOPICS.contains(mTopic)) {
- setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
- return null;
- }
-
- try {
- // Deserialize the incoming message.
- JacksonRepresentation<MessageThread> jsonRep =
- new JacksonRepresentation<MessageThread>(entity, MessageThread.class);
-
- // Get the message from the request.
- // Throw away the wrapping MessageThread because we'll create our own later.
- Message message = jsonRep.getObject().getMessage();
- if (message.getCreated() == null) {
- message.setCreated(new Date());
- }
-
- // Create the new thread.
- MessageThread newThread = MessageThread.createNew();
-
- // Force the thread id and message to be what we expect.
- message.setId(Message.generateId());
- message.setThreadId(newThread.getId());
- newThread.setMessage(message);
-
- mBackend.getThreadProvider().put(mTopic, newThread.getId(), newThread);
-
- setLocationRef(mTopic + "/" + newThread.getId());
- return new JacksonRepresentation(newThread);
-
- } catch (IOException e) {
- LOG.error("Unexpected exception: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/resources/AccountResource.java b/src/com/p4square/grow/backend/resources/AccountResource.java
deleted file mode 100644
index 2ac7061..0000000
--- a/src/com/p4square/grow/backend/resources/AccountResource.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.resources;
-
-import java.io.IOException;
-
-import org.restlet.data.Status;
-import org.restlet.resource.ServerResource;
-import org.restlet.representation.Representation;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.model.UserRecord;
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.ProvidesUserRecords;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- * Stores a document about a user.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class AccountResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(AccountResource.class);
-
- private Provider<String, UserRecord> mUserRecordProvider;
-
- private String mUserId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- final ProvidesUserRecords backend = (ProvidesUserRecords) getApplication();
- mUserRecordProvider = backend.getUserRecordProvider();
-
- mUserId = getAttribute("userId");
- }
-
- /**
- * Handle GET Requests.
- */
- @Override
- protected Representation get() {
- try {
- UserRecord result = mUserRecordProvider.get(mUserId);
-
- if (result == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- JacksonRepresentation<UserRecord> rep = new JacksonRepresentation<UserRecord>(result);
- rep.setObjectMapper(JsonEncodedProvider.MAPPER);
- return rep;
-
- } catch (IOException e) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-
- /**
- * Handle PUT requests
- */
- @Override
- protected Representation put(Representation entity) {
- try {
- JacksonRepresentation<UserRecord> representation =
- new JacksonRepresentation<>(entity, UserRecord.class);
- representation.setObjectMapper(JsonEncodedProvider.MAPPER);
- UserRecord record = representation.getObject();
-
- mUserRecordProvider.put(mUserId, record);
- setStatus(Status.SUCCESS_NO_CONTENT);
-
- } catch (IOException e) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- }
-
- return null;
- }
-}
diff --git a/src/com/p4square/grow/backend/resources/BannerResource.java b/src/com/p4square/grow/backend/resources/BannerResource.java
deleted file mode 100644
index 2b9c8e6..0000000
--- a/src/com/p4square/grow/backend/resources/BannerResource.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.resources;
-
-import java.io.IOException;
-
-import org.restlet.data.Status;
-import org.restlet.ext.jackson.JacksonRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.resource.ServerResource;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.model.Banner;
-import com.p4square.grow.provider.JsonEncodedProvider;
-import com.p4square.grow.provider.Provider;
-
-/**
- * Fetches or sets the banner string.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class BannerResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(BannerResource.class);
-
- public static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER;
-
- private Provider<String, String> mStringProvider;
-
- @Override
- public void doInit() {
- super.doInit();
-
- final GrowBackend backend = (GrowBackend) getApplication();
- mStringProvider = backend.getStringProvider();
- }
-
- /**
- * Handle GET Requests.
- */
- @Override
- protected Representation get() {
- String result = null;
- try {
- result = mStringProvider.get("banner");
-
- } catch (IOException e) {
- LOG.warn("Exception loading banner: " + e);
- }
-
- if (result == null || result.length() == 0) {
- result = "{\"html\":null}";
- }
-
- return new StringRepresentation(result);
- }
-
- /**
- * Handle PUT requests
- */
- @Override
- protected Representation put(Representation entity) {
- try {
- JacksonRepresentation<Banner> representation =
- new JacksonRepresentation<>(entity, Banner.class);
- representation.setObjectMapper(MAPPER);
-
- Banner banner = representation.getObject();
-
- mStringProvider.put("banner", MAPPER.writeValueAsString(banner));
- setStatus(Status.SUCCESS_NO_CONTENT);
-
- } catch (IOException e) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- }
-
- return null;
- }
-}
diff --git a/src/com/p4square/grow/backend/resources/SurveyResource.java b/src/com/p4square/grow/backend/resources/SurveyResource.java
deleted file mode 100644
index 8723ee2..0000000
--- a/src/com/p4square/grow/backend/resources/SurveyResource.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.resources;
-
-import java.io.IOException;
-
-import java.util.Map;
-import java.util.HashMap;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.jackson.JacksonRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.resource.ServerResource;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.model.Question;
-import com.p4square.grow.provider.JsonEncodedProvider;
-import com.p4square.grow.provider.Provider;
-
-/**
- * This resource manages assessment questions.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SurveyResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(SurveyResource.class);
-
- private static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER;
-
- private Provider<String, Question> mQuestionProvider;
- private Provider<String, String> mStringProvider;
-
- private String mQuestionId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- final GrowBackend backend = (GrowBackend) getApplication();
- mQuestionProvider = backend.getQuestionProvider();
- mStringProvider = backend.getStringProvider();
-
- mQuestionId = getAttribute("questionId");
- }
-
- /**
- * Handle GET Requests.
- */
- @Override
- protected Representation get() {
- String result = "{}";
-
- if (mQuestionId == null) {
- // TODO: List all question ids
-
- } else if (mQuestionId.equals("first")) {
- // Get the first question id from db?
- Map<?, ?> questionSummary = getQuestionsSummary();
- mQuestionId = (String) questionSummary.get("first");
-
- } else if (mQuestionId.equals("count")) {
- // Get the first question id from db?
- Map<?, ?> questionSummary = getQuestionsSummary();
-
- return new StringRepresentation("{\"count\":" +
- String.valueOf((Integer) questionSummary.get("count")) + "}");
- }
-
- if (mQuestionId != null) {
- // Get a question by id
- Question question = null;
- try {
- question = mQuestionProvider.get(mQuestionId);
- } catch (IOException e) {
- LOG.error("IOException loading question: " + e);
- }
-
- if (question == null) {
- // 404
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- JacksonRepresentation<Question> rep = new JacksonRepresentation<>(question);
- rep.setObjectMapper(MAPPER);
- return rep;
- }
-
- return new StringRepresentation(result);
- }
-
- private Map<?, ?> getQuestionsSummary() {
- try {
- // TODO: This could be better. Quick fix for provider support.
- String json = mStringProvider.get("/questions");
-
- if (json != null) {
- return MAPPER.readValue(json, Map.class);
- }
-
- } catch (IOException e) {
- LOG.info("Exception reading questions summary.", e);
- }
-
- return null;
- }
-}
diff --git a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java
deleted file mode 100644
index 7c15cfd..0000000
--- a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.resources;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.HashMap;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.resource.ServerResource;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.model.Answer;
-import com.p4square.grow.model.Question;
-import com.p4square.grow.model.RecordedAnswer;
-import com.p4square.grow.model.Score;
-import com.p4square.grow.model.UserRecord;
-import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.Provider;
-
-
-/**
- * Store the user's answers to the assessment and generate their score.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SurveyResultsResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(SurveyResultsResource.class);
-
- private static final ObjectMapper MAPPER = new ObjectMapper();
-
- static enum RequestType {
- ASSESSMENT, ANSWER
- }
-
- private CollectionProvider<String, String, String> mAnswerProvider;
- private Provider<String, Question> mQuestionProvider;
- private Provider<String, UserRecord> mUserRecordProvider;
-
- private RequestType mRequestType;
- private String mUserId;
- private String mQuestionId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- final GrowBackend backend = (GrowBackend) getApplication();
- mAnswerProvider = backend.getAnswerProvider();
- mQuestionProvider = backend.getQuestionProvider();
- mUserRecordProvider = backend.getUserRecordProvider();
-
- mUserId = getAttribute("userId");
- mQuestionId = getAttribute("questionId");
-
- mRequestType = RequestType.ASSESSMENT;
- if (mQuestionId != null) {
- mRequestType = RequestType.ANSWER;
- }
- }
-
- /**
- * Handle GET Requests.
- */
- @Override
- protected Representation get() {
- try {
- String result = null;
-
- switch (mRequestType) {
- case ANSWER:
- result = mAnswerProvider.get(mUserId, mQuestionId);
- break;
-
- case ASSESSMENT:
- result = mAnswerProvider.get(mUserId, "summary");
- if (result == null || result.length() == 0) {
- result = buildAssessment();
- }
- break;
- }
-
- if (result == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- return new StringRepresentation(result);
- } catch (IOException e) {
- LOG.error("IOException getting answer: ", e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-
- /**
- * Handle PUT requests
- */
- @Override
- protected Representation put(Representation entity) {
- boolean success = false;
-
- switch (mRequestType) {
- case ANSWER:
- try {
- mAnswerProvider.put(mUserId, mQuestionId, entity.getText());
- mAnswerProvider.put(mUserId, "lastAnswered", mQuestionId);
- mAnswerProvider.put(mUserId, "summary", null);
- success = true;
-
- } catch (Exception e) {
- LOG.warn("Caught exception putting answer: " + e.getMessage(), e);
- }
- break;
-
- default:
- setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
- return null;
- }
-
- if (success) {
- setStatus(Status.SUCCESS_NO_CONTENT);
-
- } else {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- }
-
- return null;
- }
-
- /**
- * Clear assessment results.
- */
- @Override
- protected Representation delete() {
- boolean success = false;
-
- switch (mRequestType) {
- case ANSWER:
- try {
- mAnswerProvider.put(mUserId, mQuestionId, null);
- mAnswerProvider.put(mUserId, "summary", null);
- success = true;
-
- } catch (Exception e) {
- LOG.warn("Caught exception putting answer: " + e.getMessage(), e);
- }
- break;
-
- case ASSESSMENT:
- try {
- mAnswerProvider.put(mUserId, "summary", null);
- mAnswerProvider.put(mUserId, "lastAnswered", null);
- // TODO Delete answers
-
- UserRecord record = mUserRecordProvider.get(mUserId);
- if (record != null) {
- record.setLanding("assessment");
- mUserRecordProvider.put(mUserId, record);
- }
-
- success = true;
-
- } catch (Exception e) {
- LOG.warn("Caught exception putting answer: " + e.getMessage(), e);
- }
- break;
-
- default:
- setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
- return null;
- }
-
- if (success) {
- setStatus(Status.SUCCESS_NO_CONTENT);
-
- } else {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- }
-
- return null;
-
- }
-
- /**
- * This method compiles assessment results.
- */
- private String buildAssessment() throws IOException {
- StringBuilder sb = new StringBuilder("{ ");
-
- // Last question answered
- final String lastAnswered = mAnswerProvider.get(mUserId, "lastAnswered");
- if (lastAnswered != null && lastAnswered.length() > 0) {
- sb.append("\"lastAnswered\": \"" + lastAnswered + "\", ");
- }
-
- // Compute score
- Map<String, String> row = mAnswerProvider.query(mUserId);
- if (row.size() > 0) {
- Score score = new Score();
- boolean scoringDone = false;
- int totalAnswers = 0;
- for (Map.Entry<String, String> c : row.entrySet()) {
- if (c.getKey().equals("lastAnswered") || c.getKey().equals("summary")) {
- continue;
- }
-
- try {
- Question question = mQuestionProvider.get(c.getKey());
- RecordedAnswer userAnswer = MAPPER.readValue(c.getValue(), RecordedAnswer.class);
-
- if (question == null) {
- LOG.warn("Answer for unknown question: " + c.getKey());
- continue;
- }
-
- LOG.debug("Scoring questionId: " + c.getKey());
- scoringDone = !question.scoreAnswer(score, userAnswer);
-
- } catch (Exception e) {
- LOG.error("Failed to score question: {userid: \"" + mUserId +
- "\", questionid:\"" + c.getKey() +
- "\", userAnswer:\"" + c.getValue() + "\"}", e);
- }
-
- totalAnswers++;
- }
-
- sb.append("\"score\":" + score.getScore());
- sb.append(", \"sum\":" + score.getSum());
- sb.append(", \"count\":" + score.getCount());
- sb.append(", \"totalAnswers\":" + totalAnswers);
- sb.append(", \"result\":\"" + score.toString() + "\"");
- }
-
- sb.append(" }");
- String summary = sb.toString();
-
- // Persist summary
- mAnswerProvider.put(mUserId, "summary", summary);
-
- return summary;
- }
-}
diff --git a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java b/src/com/p4square/grow/backend/resources/TrainingRecordResource.java
deleted file mode 100644
index 51ba56a..0000000
--- a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.resources;
-
-import java.io.IOException;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.resource.ServerResource;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.backend.GrowBackend;
-
-import com.p4square.grow.model.Chapter;
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.model.VideoRecord;
-import com.p4square.grow.model.TrainingRecord;
-
-import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.ProvidesAssessments;
-import com.p4square.grow.provider.ProvidesTrainingRecords;
-
-import com.p4square.grow.model.Score;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class TrainingRecordResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(TrainingRecordResource.class);
- private static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER;
-
- static enum RequestType {
- SUMMARY, VIDEO
- }
-
- private Provider<String, TrainingRecord> mTrainingRecordProvider;
- private CollectionProvider<String, String, String> mAnswerProvider;
-
- private RequestType mRequestType;
- private String mUserId;
- private String mVideoId;
- private TrainingRecord mRecord;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mTrainingRecordProvider = ((ProvidesTrainingRecords) getApplication()).getTrainingRecordProvider();
- mAnswerProvider = ((ProvidesAssessments) getApplication()).getAnswerProvider();
-
- mUserId = getAttribute("userId");
- mVideoId = getAttribute("videoId");
-
- try {
- Playlist defaultPlaylist = ((ProvidesTrainingRecords) getApplication()).getDefaultPlaylist();
-
- mRecord = mTrainingRecordProvider.get(mUserId);
- if (mRecord == null) {
- mRecord = new TrainingRecord();
- mRecord.setPlaylist(defaultPlaylist);
- skipAssessedChapters(mUserId, mRecord);
- } else {
- // Merge the playlist with the most recent version.
- mRecord.getPlaylist().merge(defaultPlaylist);
- }
-
- } catch (IOException e) {
- LOG.error("IOException loading TrainingRecord: " + e.getMessage(), e);
- mRecord = null;
- }
-
- mRequestType = RequestType.SUMMARY;
- if (mVideoId != null) {
- mRequestType = RequestType.VIDEO;
- }
- }
-
- /**
- * Handle GET Requests.
- */
- @Override
- protected Representation get() {
- JacksonRepresentation<?> rep = null;
-
- if (mRecord == null) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
-
- switch (mRequestType) {
- case VIDEO:
- VideoRecord video = mRecord.getPlaylist().find(mVideoId);
- if (video == null) {
- break; // Fall through and return 404
- }
- rep = new JacksonRepresentation<VideoRecord>(video);
- break;
-
- case SUMMARY:
- rep = new JacksonRepresentation<TrainingRecord>(mRecord);
- break;
- }
-
- if (rep == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
-
- } else {
- rep.setObjectMapper(JsonEncodedProvider.MAPPER);
- return rep;
- }
- }
-
- /**
- * Handle PUT requests
- */
- @Override
- protected Representation put(Representation entity) {
- if (mRecord == null) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
-
- switch (mRequestType) {
- case VIDEO:
- try {
- JacksonRepresentation<VideoRecord> representation =
- new JacksonRepresentation<>(entity, VideoRecord.class);
- representation.setObjectMapper(JsonEncodedProvider.MAPPER);
- VideoRecord update = representation.getObject();
- VideoRecord video = mRecord.getPlaylist().find(mVideoId);
-
- if (video == null) {
- // TODO: Video isn't on their playlist...
- LOG.warn("Skipping video completion for video missing from playlist.");
-
- } else if (update.getComplete() && !video.getComplete()) {
- // Video was newly completed
- video.complete();
- mRecord.setLastVideo(mVideoId);
-
- mTrainingRecordProvider.put(mUserId, mRecord);
- }
-
- setStatus(Status.SUCCESS_NO_CONTENT);
-
- } catch (Exception e) {
- LOG.warn("Caught exception updating training record: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- }
- break;
-
- default:
- setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
- }
-
- return null;
- }
-
- private Score getAssessedScore(String userId) throws IOException {
- // Get the user's score.
- Score assessedScore = new Score(0, 0);
-
- String summaryString = mAnswerProvider.get(userId, "summary");
- if (summaryString == null) {
- throw new IOException("Asked to create training record for unassessed user " + userId);
- }
-
- Map<?,?> summary = MAPPER.readValue(summaryString, Map.class);
-
- if (summary.containsKey("sum") && summary.containsKey("count")) {
- double sum = (Double) summary.get("sum");
- int count = (Integer) summary.get("count");
- assessedScore = new Score(sum, count);
- }
-
- return assessedScore;
- }
-
- /**
- * Mark the chapters which the user assessed through as not required.
- */
- private void skipAssessedChapters(String userId, TrainingRecord record) {
- // Get the user's score.
- Score assessedScore = new Score(0, 0);
-
- try {
- assessedScore = getAssessedScore(userId);
- } catch (IOException e) {
- LOG.error("IOException fetching assessment record for " + userId, e);
- return;
- }
-
- // Mark the correct videos as not required.
- Playlist playlist = record.getPlaylist();
-
- for (Map.Entry<String, Chapter> entry : playlist.getChaptersMap().entrySet()) {
- String chapterId = entry.getKey();
- Chapter chapter = entry.getValue();
- boolean required;
-
- if ("introduction".equals(chapter)) {
- // Introduction chapter is always required
- required = true;
-
- } else {
- // Chapter required if the floor of the score is <= the chapter's numeric value.
- required = assessedScore.floor() <= Score.numericScore(chapterId);
- }
-
- if (!required) {
- for (VideoRecord video : chapter.getVideos().values()) {
- video.setRequired(required);
- }
- }
- }
- }
-}
diff --git a/src/com/p4square/grow/backend/resources/TrainingResource.java b/src/com/p4square/grow/backend/resources/TrainingResource.java
deleted file mode 100644
index 6efdfab..0000000
--- a/src/com/p4square/grow/backend/resources/TrainingResource.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.backend.resources;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.restlet.data.Status;
-import org.restlet.resource.ServerResource;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.backend.db.CassandraDatabase;
-
-import com.p4square.grow.provider.CollectionProvider;
-/**
- * This resource returns a listing of training items for a particular level.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class TrainingResource extends ServerResource {
- private final static Logger LOG = Logger.getLogger(TrainingResource.class);
-
- private CollectionProvider<String, String, String> mVideoProvider;
-
- private String mLevel;
- private String mVideoId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- GrowBackend backend = (GrowBackend) getApplication();
- mVideoProvider = backend.getVideoProvider();
-
- mLevel = getAttribute("level");
- mVideoId = getAttribute("videoId");
- }
-
- /**
- * Handle GET Requests.
- */
- @Override
- protected Representation get() {
- String result = null;
-
- if (mLevel == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- try {
- if (mVideoId == null) {
- // Get all videos
- // TODO: This could be improved, but this is the quickest way to get
- // providers working.
- Map<String, String> videos = mVideoProvider.query(mLevel);
- if (videos.size() > 0) {
- StringBuilder sb = new StringBuilder("{ \"level\": \"" + mLevel + "\"");
- sb.append(", \"videos\": [");
- boolean first = true;
- for (String value : videos.values()) {
- if (!first) {
- sb.append(", ");
- }
- sb.append(value);
- first = false;
- }
- sb.append("] }");
- result = sb.toString();
- }
-
- } else {
- // Get single video
- result = mVideoProvider.get(mLevel, mVideoId);
- }
-
- if (result == null) {
- // 404
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- return new StringRepresentation(result);
-
- } catch (IOException e) {
- LOG.error("IOException fetch video: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-}
diff --git a/src/com/p4square/grow/ccb/CCBProgressReporter.java b/src/com/p4square/grow/ccb/CCBProgressReporter.java
deleted file mode 100644
index d2826eb..0000000
--- a/src/com/p4square/grow/ccb/CCBProgressReporter.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package com.p4square.grow.ccb;
-
-import com.p4square.ccbapi.CCBAPI;
-import com.p4square.ccbapi.model.*;
-import com.p4square.grow.frontend.ProgressReporter;
-import com.p4square.grow.model.Score;
-import org.apache.log4j.Logger;
-import org.restlet.security.User;
-
-import java.io.IOException;
-import java.time.LocalDate;
-import java.time.ZoneId;
-import java.util.Date;
-
-/**
- * A ProgressReporter which records progress in CCB.
- *
- * Except not really, because it's not implemented yet.
- * This is just a placeholder until ccb-api-client-java has support for updating an individual.
- */
-public class CCBProgressReporter implements ProgressReporter {
-
- private static final Logger LOG = Logger.getLogger(CCBProgressReporter.class);
-
- private static final String GROW_LEVEL = "GrowLevelTrain";
- private static final String GROW_ASSESSMENT = "GrowLevelAsmnt";
-
- private final CCBAPI mAPI;
- private final CustomFieldCache mCache;
-
- public CCBProgressReporter(final CCBAPI api, final CustomFieldCache cache) {
- mAPI = api;
- mCache = cache;
- }
-
- @Override
- public void reportAssessmentComplete(final User user, final String level, final Date date, final String results) {
- if (!(user instanceof CCBUser)) {
- throw new IllegalArgumentException("Expected CCBUser but got " + user.getClass().getCanonicalName());
- }
- final CCBUser ccbuser = (CCBUser) user;
-
- updateLevelAndDate(ccbuser, GROW_ASSESSMENT, level, date);
- }
-
- @Override
- public void reportChapterComplete(final User user, final String chapter, final Date date) {
- if (!(user instanceof CCBUser)) {
- throw new IllegalArgumentException("Expected CCBUser but got " + user.getClass().getCanonicalName());
- }
- final CCBUser ccbuser = (CCBUser) user;
-
- // Only update the level if it is increasing.
- final CustomPulldownFieldValue currentLevel = ccbuser.getProfile()
- .getCustomPulldownFields().getByLabel(GROW_LEVEL);
-
- if (currentLevel != null) {
- if (Score.numericScore(chapter) <= Score.numericScore(currentLevel.getSelection().getLabel())) {
- LOG.info("Not updating level for " + user.getIdentifier()
- + " because current level (" + currentLevel.getSelection().getLabel()
- + ") is greater than new level (" + chapter + ")");
- return;
- }
- }
-
- updateLevelAndDate(ccbuser, GROW_LEVEL, chapter, date);
- }
-
- private void updateLevelAndDate(final CCBUser user, final String field, final String level, final Date date) {
- boolean modified = false;
-
- final UpdateIndividualProfileRequest req = new UpdateIndividualProfileRequest()
- .withIndividualId(user.getProfile().getId());
-
- final CustomField pulldownField = mCache.getIndividualPulldownByLabel(field);
- if (pulldownField != null) {
- final LookupTableType type = LookupTableType.valueOf(pulldownField.getName().toUpperCase());
- final LookupTableItem item = mCache.getPulldownItemByName(type, level);
- if (item != null) {
- req.withCustomPulldownField(pulldownField.getName(), item.getId());
- modified = true;
- }
- }
-
- final CustomField dateField = mCache.getDateFieldByLabel(field);
- if (dateField != null) {
- req.withCustomDateField(dateField.getName(), date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
- modified = true;
- }
-
- try {
- // Only update if a field exists.
- if (modified) {
- mAPI.updateIndividualProfile(req);
- }
-
- } catch (IOException e) {
- LOG.error("updateIndividual failed for " + user.getIdentifier()
- + ", field " + field
- + ", level " + level
- + ", date " + date.toString());
- }
- }
-}
diff --git a/src/com/p4square/grow/ccb/CCBUser.java b/src/com/p4square/grow/ccb/CCBUser.java
deleted file mode 100644
index 7313172..0000000
--- a/src/com/p4square/grow/ccb/CCBUser.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.p4square.grow.ccb;
-
-import com.p4square.ccbapi.model.IndividualProfile;
-import org.restlet.security.User;
-
-/**
- * CCBUser is an adapter between a CCB IndividualProfile and a Restlet User.
- *
- * Note: CCBUser prefixes the user's identifier with "CCB-". This is done to
- * ensure the identifier does not collide with identifiers from other
- * systems.
- */
-public class CCBUser extends User {
-
- private final IndividualProfile mProfile;
-
- /**
- * Wrap an IndividualProfile inside a User object.
- *
- * @param profile The CCB IndividualProfile for the user.
- */
- public CCBUser(final IndividualProfile profile) {
- mProfile = profile;
-
- setIdentifier("CCB-" + mProfile.getId());
- setFirstName(mProfile.getFirstName());
- setLastName(mProfile.getLastName());
- setEmail(mProfile.getEmail());
- }
-
- /**
- * @return The IndividualProfile of the user.
- */
- public IndividualProfile getProfile() {
- return mProfile;
- }
-}
diff --git a/src/com/p4square/grow/ccb/CCBUserVerifier.java b/src/com/p4square/grow/ccb/CCBUserVerifier.java
deleted file mode 100644
index db10b75..0000000
--- a/src/com/p4square/grow/ccb/CCBUserVerifier.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.p4square.grow.ccb;
-
-import com.p4square.ccbapi.CCBAPI;
-import com.p4square.ccbapi.model.GetIndividualProfilesRequest;
-import com.p4square.ccbapi.model.GetIndividualProfilesResponse;
-import org.apache.log4j.Logger;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.security.Verifier;
-
-/**
- * CCBUserVerifier authenticates a user through the CCB individual_profile_from_login_password API.
- */
-public class CCBUserVerifier implements Verifier {
- private static final Logger LOG = Logger.getLogger(CCBUserVerifier.class);
-
- private final CCBAPI mAPI;
-
- public CCBUserVerifier(final CCBAPI api) {
- mAPI = api;
- }
-
- @Override
- public int verify(Request request, Response response) {
- if (request.getChallengeResponse() == null) {
- return RESULT_MISSING; // no credentials
- }
-
- final String username = request.getChallengeResponse().getIdentifier();
- final char[] password = request.getChallengeResponse().getSecret();
-
- try {
- GetIndividualProfilesResponse resp = mAPI.getIndividualProfiles(
- new GetIndividualProfilesRequest().withLoginPassword(username, password));
-
- if (resp.getIndividuals().size() == 1) {
- // Wrap the IndividualProfile up in an User and update the user on the request.
- final CCBUser user = new CCBUser(resp.getIndividuals().get(0));
- LOG.info("Successfully authenticated " + user.getIdentifier());
- request.getClientInfo().setUser(user);
- return RESULT_VALID;
- }
-
- } catch (Exception e) {
- LOG.error("CCB API Exception: " + e, e);
- }
-
- return RESULT_INVALID; // Invalid credentials
- }
-}
diff --git a/src/com/p4square/grow/ccb/ChurchCommunityBuilderIntegrationDriver.java b/src/com/p4square/grow/ccb/ChurchCommunityBuilderIntegrationDriver.java
deleted file mode 100644
index fc6148f..0000000
--- a/src/com/p4square/grow/ccb/ChurchCommunityBuilderIntegrationDriver.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.p4square.grow.ccb;
-
-import com.codahale.metrics.MetricRegistry;
-import com.p4square.ccbapi.CCBAPI;
-import com.p4square.ccbapi.CCBAPIClient;
-import com.p4square.grow.config.Config;
-import com.p4square.grow.frontend.IntegrationDriver;
-import com.p4square.grow.frontend.ProgressReporter;
-import org.restlet.Context;
-import org.restlet.security.Verifier;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-/**
- * The ChurchCommunityBuilderIntegrationDriver is used to integrate Grow with Church Community Builder.
- */
-public class ChurchCommunityBuilderIntegrationDriver implements IntegrationDriver {
-
- private final Context mContext;
- private final MetricRegistry mMetricRegistry;
- private final Config mConfig;
-
- private final CCBAPI mAPI;
-
- private final CCBProgressReporter mProgressReporter;
-
- public ChurchCommunityBuilderIntegrationDriver(final Context context) {
- mContext = context;
- mConfig = (Config) context.getAttributes().get("com.p4square.grow.config");
- mMetricRegistry = (MetricRegistry) context.getAttributes().get("com.p4square.grow.metrics");
-
- try {
- CCBAPI api = new CCBAPIClient(new URI(mConfig.getString("CCBAPIURL", "")),
- mConfig.getString("CCBAPIUser", ""),
- mConfig.getString("CCBAPIPassword", ""));
-
- if (mMetricRegistry != null) {
- api = new MonitoredCCBAPI(api, mMetricRegistry);
- }
-
- mAPI = api;
-
- final CustomFieldCache cache = new CustomFieldCache(mAPI);
- mProgressReporter = new CCBProgressReporter(mAPI, cache);
-
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public Verifier newUserAuthenticationVerifier() {
- return new CCBUserVerifier(mAPI);
- }
-
- @Override
- public ProgressReporter getProgressReporter() {
- return mProgressReporter;
- }
-}
diff --git a/src/com/p4square/grow/ccb/CustomFieldCache.java b/src/com/p4square/grow/ccb/CustomFieldCache.java
deleted file mode 100644
index d93e6d9..0000000
--- a/src/com/p4square/grow/ccb/CustomFieldCache.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package com.p4square.grow.ccb;
-
-import com.p4square.ccbapi.CCBAPI;
-import com.p4square.ccbapi.model.*;
-import org.apache.log4j.Logger;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-/**
- * CustomFieldCache maintains an index from custom field labels to names.
- */
-public class CustomFieldCache {
-
- private static final Logger LOG = Logger.getLogger(CustomFieldCache.class);
-
- private final CCBAPI mAPI;
-
- private CustomFieldCollection<CustomField> mTextFields;
- private CustomFieldCollection<CustomField> mDateFields;
- private CustomFieldCollection<CustomField> mIndividualPulldownFields;
- private CustomFieldCollection<CustomField> mGroupPulldownFields;
-
- private final Map<LookupTableType, Map<String, LookupTableItem>> mItemByNameTable;
-
- public CustomFieldCache(final CCBAPI api) {
- mAPI = api;
- mTextFields = new CustomFieldCollection<>();
- mDateFields = new CustomFieldCollection<>();
- mIndividualPulldownFields = new CustomFieldCollection<>();
- mGroupPulldownFields = new CustomFieldCollection<>();
- mItemByNameTable = new HashMap<>();
- }
-
- public CustomField getTextFieldByLabel(final String label) {
- if (mTextFields.size() == 0) {
- refresh();
- }
- return mTextFields.getByLabel(label);
- }
-
- public CustomField getDateFieldByLabel(final String label) {
- if (mDateFields.size() == 0) {
- refresh();
- }
- return mDateFields.getByLabel(label);
- }
-
- public CustomField getIndividualPulldownByLabel(final String label) {
- if (mIndividualPulldownFields.size() == 0) {
- refresh();
- }
- return mIndividualPulldownFields.getByLabel(label);
- }
-
- public CustomField getGroupPulldownByLabel(final String label) {
- if (mGroupPulldownFields.size() == 0) {
- refresh();
- }
- return mGroupPulldownFields.getByLabel(label);
- }
-
- public LookupTableItem getPulldownItemByName(final LookupTableType type, final String name) {
- Map<String, LookupTableItem> items = mItemByNameTable.get(type);
- if (items == null) {
- if (!cacheLookupTable(type)) {
- return null;
- }
- items = mItemByNameTable.get(type);
- }
-
- return items.get(name.toLowerCase());
- }
-
- private synchronized void refresh() {
- try {
- // Get all of the custom fields.
- final GetCustomFieldLabelsResponse resp = mAPI.getCustomFieldLabels();
-
- final CustomFieldCollection<CustomField> newTextFields = new CustomFieldCollection<>();
- final CustomFieldCollection<CustomField> newDateFields = new CustomFieldCollection<>();
- final CustomFieldCollection<CustomField> newIndPulldownFields = new CustomFieldCollection<>();
- final CustomFieldCollection<CustomField> newGrpPulldownFields = new CustomFieldCollection<>();
-
- for (final CustomField field : resp.getCustomFields()) {
- if (field.getName().startsWith("udf_ind_text_")) {
- newTextFields.add(field);
- } else if (field.getName().startsWith("udf_ind_date_")) {
- newDateFields.add(field);
- } else if (field.getName().startsWith("udf_ind_pulldown_")) {
- newIndPulldownFields.add(field);
- } else if (field.getName().startsWith("udf_grp_pulldown_")) {
- newGrpPulldownFields.add(field);
- } else {
- LOG.warn("Unknown custom field type " + field.getName());
- }
- }
-
- this.mTextFields = newTextFields;
- this.mDateFields = newDateFields;
- this.mIndividualPulldownFields = newIndPulldownFields;
- this.mGroupPulldownFields = newGrpPulldownFields;
-
- } catch (IOException e) {
- // Error fetching labels.
- LOG.error("Error fetching custom fields: " + e.getMessage(), e);
- }
- }
-
- private synchronized boolean cacheLookupTable(final LookupTableType type) {
- try {
- final GetLookupTableResponse resp = mAPI.getLookupTable(new GetLookupTableRequest().withType(type));
- mItemByNameTable.put(type, resp.getItems().stream().collect(
- Collectors.toMap(item -> item.getName().toLowerCase(), Function.identity())));
- return true;
-
- } catch (IOException e) {
- LOG.error("Exception caching lookup table of type " + type, e);
- }
-
- return false;
- }
-}
diff --git a/src/com/p4square/grow/ccb/MonitoredCCBAPI.java b/src/com/p4square/grow/ccb/MonitoredCCBAPI.java
deleted file mode 100644
index 43b6433..0000000
--- a/src/com/p4square/grow/ccb/MonitoredCCBAPI.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.p4square.grow.ccb;
-
-import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.Timer;
-import com.p4square.ccbapi.CCBAPI;
-import com.p4square.ccbapi.model.*;
-
-import java.io.IOException;
-
-/**
- * MonitoredCCBAPI is a CCBAPI decorator which records metrics for each API call.
- */
-public class MonitoredCCBAPI implements CCBAPI {
-
- private final CCBAPI mAPI;
- private final MetricRegistry mMetricRegistry;
-
- public MonitoredCCBAPI(final CCBAPI api, final MetricRegistry metricRegistry) {
- if (api == null) {
- throw new IllegalArgumentException("api must not be null.");
- }
- mAPI = api;
-
- if (metricRegistry == null) {
- throw new IllegalArgumentException("metricRegistry must not be null.");
- }
- mMetricRegistry = metricRegistry;
- }
-
- @Override
- public GetCustomFieldLabelsResponse getCustomFieldLabels() throws IOException {
- final Timer.Context timer = mMetricRegistry.timer("CCBAPI.getCustomFieldLabels.time").time();
- boolean success = false;
- try {
- final GetCustomFieldLabelsResponse resp = mAPI.getCustomFieldLabels();
- success = true;
- return resp;
- } finally {
- timer.stop();
- mMetricRegistry.counter("CCBAPI.getCustomFieldLabels.success").inc(success ? 1 : 0);
- mMetricRegistry.counter("CCBAPI.getCustomFieldLabels.failure").inc(!success ? 1 : 0);
- }
- }
-
- @Override
- public GetLookupTableResponse getLookupTable(final GetLookupTableRequest request) throws IOException {
- final Timer.Context timer = mMetricRegistry.timer("CCBAPI.getLookupTable.time").time();
- boolean success = false;
- try {
- final GetLookupTableResponse resp = mAPI.getLookupTable(request);
- success = true;
- return resp;
- } finally {
- timer.stop();
- mMetricRegistry.counter("CCBAPI.getLookupTable.success").inc(success ? 1 : 0);
- mMetricRegistry.counter("CCBAPI.getLookupTable.failure").inc(!success ? 1 : 0);
- }
- }
-
- @Override
- public GetIndividualProfilesResponse getIndividualProfiles(GetIndividualProfilesRequest request)
- throws IOException {
- final Timer.Context timer = mMetricRegistry.timer("CCBAPI.getIndividualProfiles").time();
- boolean success = false;
- try {
- final GetIndividualProfilesResponse resp = mAPI.getIndividualProfiles(request);
- mMetricRegistry.counter("CCBAPI.getIndividualProfiles.count").inc(resp.getIndividuals().size());
- success = true;
- return resp;
- } finally {
- timer.stop();
- mMetricRegistry.counter("CCBAPI.getIndividualProfiles.success").inc(success ? 1 : 0);
- mMetricRegistry.counter("CCBAPI.getIndividualProfiles.failure").inc(!success ? 1 : 0);
- }
- }
-
- @Override
- public UpdateIndividualProfileResponse updateIndividualProfile(UpdateIndividualProfileRequest request) throws IOException {
- final Timer.Context timer = mMetricRegistry.timer("CCBAPI.updateIndividualProfile").time();
- boolean success = false;
- try {
- final UpdateIndividualProfileResponse resp = mAPI.updateIndividualProfile(request);
- success = true;
- return resp;
- } finally {
- timer.stop();
- mMetricRegistry.counter("CCBAPI.updateIndividualProfile.success").inc(success ? 1 : 0);
- mMetricRegistry.counter("CCBAPI.updateIndividualProfile.failure").inc(!success ? 1 : 0);
- }
- }
-
- @Override
- public void close() throws IOException {
- mAPI.close();
- }
-}
diff --git a/src/com/p4square/grow/config/Config.java b/src/com/p4square/grow/config/Config.java
deleted file mode 100644
index 2fc2ea3..0000000
--- a/src/com/p4square/grow/config/Config.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.config;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Properties;
-
-import org.apache.log4j.Logger;
-
-/**
- * Manage configuration for an application.
- *
- * Config reads one or more property files as the application config. Duplicate
- * properties loaded later override properties loaded earlier. Config has the
- * concept of a domain to distinguish settings for development and production.
- * The default domain is prod for production. Domain can be any String such as
- * dev for development or test for testing.
- *
- * The property files are processed like java.util.Properties except that the
- * keys are specified as DOMAIN.KEY. An asterisk (*) can be used in place of a
- * domain to indicate it should apply to all domains. If a domain specific entry
- * exists for the current domain, it will override any global config.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Config {
- private static final Logger LOG = Logger.getLogger(Config.class);
-
- private String mDomain;
- private Properties mProperties;
-
- /**
- * Construct a new Config object.
- *
- * Sets the domain to the value of the system property CONFIG_DOMAIN, if present.
- * If the system property is not set then the environment variable CONFIG_DOMAIN is checked.
- * If neither are set the domain defaults to prod.
- */
- public Config() {
- // Check the command line for a domain property.
- mDomain = System.getProperty("CONFIG_DOMAIN");
-
- // If the domain was not set with a property, check for an environment variable.
- if (mDomain == null) {
- mDomain = System.getenv("CONFIG_DOMAIN");
- }
-
- // If neither were set, default to prod
- if (mDomain == null) {
- mDomain = "prod";
- }
-
- mProperties = new Properties();
- }
-
- /**
- * Change the domain from the default string "prod".
- *
- * @param domain The new domain.
- */
- public void setDomain(String domain) {
- LOG.info("Setting Config domain to " + domain);
- mDomain = domain;
- }
-
- /**
- * @return the current domain.
- */
- public String getDomain() {
- return mDomain;
- }
-
- /**
- * Load properties from a file.
- * Any exception are logged and suppressed.
- */
- public void updateConfig(String propertyFilename) {
- final File propFile = new File(propertyFilename);
-
- LOG.info("Loading properties from " + propFile);
-
- try {
- InputStream in = new FileInputStream(propFile);
- updateConfig(in);
-
- } catch (IOException e) {
- LOG.error("Could not load properties file: " + e.getMessage(), e);
- }
- }
-
- /**
- * Load properties from an InputStream.
- * This method closes the InputStream when it completes.
- *
- * @param in The InputStream
- */
- public void updateConfig(InputStream in) throws IOException {
- LOG.info("Loading properties from InputStream");
- mProperties.load(in);
- in.close();
- }
-
- /**
- * Get a String from the config.
- *
- * @return The config value or null if it is not found.
- */
- public String getString(String key) {
- return getString(key, null);
- }
-
- /**
- * Get a String from the config.
- *
- * @return The config value or defaultValue if it can not be found.
- */
- public String getString(final String key, final String defaultValue) {
- String result;
-
- // Command line properties trump all.
- result = System.getProperty(key);
- if (result != null) {
- LOG.debug("Reading System.getProperty(" + key + "). Got result = { " + result + " }");
- return result;
- }
-
- // Environment variables can also override configs
- result = System.getenv(key);
- if (result != null) {
- LOG.debug("Reading System.getenv(" + key + "). Got result = { " + result + " }");
- return result;
- }
-
- final String domainKey = mDomain + "." + key;
- result = mProperties.getProperty(domainKey);
- if (result != null) {
- LOG.debug("Reading config for key = { " + key + " }. Got result = { " + result + " }");
- return result;
- }
-
- final String globalKey = "*." + key;
- result = mProperties.getProperty(globalKey);
- if (result != null) {
- LOG.debug("Reading config for key = { " + key + " }. Got result = { " + result + " }");
- return result;
- }
-
- LOG.debug("Reading config for key = { " + key + " }. Got default value = { " + defaultValue + " }");
- return defaultValue;
- }
-
- /**
- * Get an integer from the config.
- *
- * @return The config value or Integer.MIN_VALUE if the key is not present or the
- * config can not be parsed.
- */
- public int getInt(String key) {
- return getInt(key, Integer.MIN_VALUE);
- }
-
- /**
- * Get an integer from the config.
- *
- * @return The config value or defaultValue if the key is not present or the
- * config can not be parsed.
- */
- public int getInt(String key, int defaultValue) {
- final String propertyValue = getString(key);
-
- if (propertyValue != null) {
- try {
- final int result = Integer.valueOf(propertyValue);
- return result;
-
- } catch (NumberFormatException e) {
- LOG.warn("Expected property to be an integer: "
- + key + " = { " + propertyValue + " }");
- }
- }
-
- return defaultValue;
- }
-
- public boolean getBoolean(String key) {
- return getBoolean(key, false);
- }
-
- public boolean getBoolean(String key, boolean defaultValue) {
- final String propertyValue = getString(key);
-
- if (propertyValue != null) {
- return (propertyValue.charAt(0) & 0xDF) == 'T';
- }
-
- return defaultValue;
- }
-}
diff --git a/src/com/p4square/grow/frontend/AccountRedirectResource.java b/src/com/p4square/grow/frontend/AccountRedirectResource.java
deleted file mode 100644
index be2ae65..0000000
--- a/src/com/p4square/grow/frontend/AccountRedirectResource.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.resource.ServerResource;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-import com.p4square.grow.config.Config;
-import com.p4square.grow.model.UserRecord;
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.DelegateProvider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- * This resource simply redirects the user to either the assessment
- * or the training page.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class AccountRedirectResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(AccountRedirectResource.class);
-
- private Config mConfig;
- private Provider<String, UserRecord> mUserRecordProvider;
-
- // Fields pertaining to this request.
- private String mUserId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- GrowFrontend growFrontend = (GrowFrontend) getApplication();
- mConfig = growFrontend.getConfig();
-
- mUserRecordProvider = new DelegateProvider<String, String, UserRecord>(
- new JsonRequestProvider<UserRecord>(getContext().getClientDispatcher(),
- UserRecord.class)) {
- @Override
- public String makeKey(String userid) {
- return getBackendEndpoint() + "/accounts/" + userid;
- }
- };
-
- mUserId = getRequest().getClientInfo().getUser().getIdentifier();
- }
-
- /**
- * Redirect to the correct landing.
- */
- @Override
- protected Representation get() {
- if (mUserId == null || mUserId.length() == 0) {
- // This shouldn't happen, but I want to be safe because of the DB insert below.
- setStatus(Status.CLIENT_ERROR_FORBIDDEN);
- return new ErrorPage("Not Authenticated!");
- }
-
- try {
- // Fetch account Map.
- UserRecord user = null;
- try {
- user = mUserRecordProvider.get(mUserId);
- } catch (NotFoundException e) {
- // User record doesn't exist, so create a new one.
- user = new UserRecord(getRequest().getClientInfo().getUser());
- mUserRecordProvider.put(mUserId, user);
- }
-
- // Check for the new believers cookie
- String cookie = getRequest().getCookies().getFirstValue(NewBelieverResource.COOKIE_NAME);
- if (cookie != null && cookie.length() != 0) {
- user.setLanding("training");
- user.setNewBeliever(true);
- mUserRecordProvider.put(mUserId, user);
- }
-
- String landing = user.getLanding();
- if (landing == null) {
- landing = "assessment";
- }
-
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/account/" + landing;
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- /**
- * @return The backend endpoint URI
- */
- private String getBackendEndpoint() {
- return mConfig.getString("backendUri", "riap://component/backend");
- }
-}
diff --git a/src/com/p4square/grow/frontend/AssessmentResetPage.java b/src/com/p4square/grow/frontend/AssessmentResetPage.java
deleted file mode 100644
index 519b135..0000000
--- a/src/com/p4square/grow/frontend/AssessmentResetPage.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.Map;
-
-import freemarker.template.Template;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-import com.p4square.fmfacade.json.JsonRequestClient;
-import com.p4square.fmfacade.json.JsonResponse;
-import com.p4square.fmfacade.json.ClientException;
-
-import com.p4square.grow.config.Config;
-
-/**
- * This page delete's the current user's assessment.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class AssessmentResetPage extends FreeMarkerPageResource {
- private static final Logger LOG = Logger.getLogger(AssessmentResetPage.class);
-
- private GrowFrontend mGrowFrontend;
- private Config mConfig;
- private JsonRequestClient mJsonClient;
-
- private String mUserId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mGrowFrontend = (GrowFrontend) getApplication();
- mConfig = mGrowFrontend.getConfig();
-
- mJsonClient = new JsonRequestClient(getContext().getClientDispatcher());
-
- mUserId = getRequest().getClientInfo().getUser().getIdentifier();
- }
-
- /**
- * Return the login page.
- */
- @Override
- protected Representation get() {
- try {
- // Get the assessment results
- JsonResponse response = backendDelete("/accounts/" + mUserId + "/assessment");
- if (!response.getStatus().isSuccess()) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.BACKEND_ERROR;
- }
-
- String nextPage = mConfig.getString("dynamicRoot", "")
- + "/account/assessment/question/first";
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- /**
- * @return The backend endpoint URI
- */
- private String getBackendEndpoint() {
- return mConfig.getString("backendUri", "riap://component/backend");
- }
-
- /**
- * Helper method to send a GET to the backend.
- */
- private JsonResponse backendDelete(final String uri) {
- LOG.debug("Sending backend GET " + uri);
-
- final JsonResponse response = mJsonClient.delete(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());
- }
-
- return response;
- }
-}
diff --git a/src/com/p4square/grow/frontend/AssessmentResultsPage.java b/src/com/p4square/grow/frontend/AssessmentResultsPage.java
deleted file mode 100644
index f1c924b..0000000
--- a/src/com/p4square/grow/frontend/AssessmentResultsPage.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.Date;
-import java.util.Map;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.p4square.f1oauth.FellowshipOneIntegrationDriver;
-import freemarker.template.Template;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-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;
-import org.restlet.security.User;
-
-/**
- * This page fetches the user's final score and displays the transitional page between
- * the assessment and the videos.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class AssessmentResultsPage extends FreeMarkerPageResource {
- private static final Logger LOG = Logger.getLogger(AssessmentResultsPage.class);
-
- private GrowFrontend mGrowFrontend;
- private Config mConfig;
- private JsonRequestClient mJsonClient;
-
- private String mUserId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mGrowFrontend = (GrowFrontend) getApplication();
- mConfig = mGrowFrontend.getConfig();
-
- mJsonClient = new JsonRequestClient(getContext().getClientDispatcher());
-
- mUserId = getRequest().getClientInfo().getUser().getIdentifier();
- }
-
- /**
- * Return the login page.
- */
- @Override
- protected Representation get() {
- Template t = mGrowFrontend.getTemplate("templates/assessment-results.ftl");
-
- try {
- if (t == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return ErrorPage.TEMPLATE_NOT_FOUND;
- }
-
- Map<String, Object> root = getRootObject();
-
- // Get the assessment results
- JsonResponse response = backendGet("/accounts/" + mUserId + "/assessment");
- if (!response.getStatus().isSuccess()) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.BACKEND_ERROR;
- }
-
- final String score = (String) response.getMap().get("result");
- if (score == null) {
- // Odd... send them to the first questions
- String nextPage = mConfig.getString("dynamicRoot", "")
- + "/account/assessment/question/first";
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
- }
-
- // Publish results in F1
- publishScoreInF1(response.getMap());
-
- root.put("stage", score);
- return new TemplateRepresentation(t, root, MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- private void publishScoreInF1(Map results) {
- final ProgressReporter reporter = mGrowFrontend.getThirdPartyIntegrationFactory().getProgressReporter();
-
- try {
- final User user = getRequest().getClientInfo().getUser();
- final String level = results.get("result").toString();
- final Date completionDate = new Date();
- final String data = JsonEncodedProvider.MAPPER.writeValueAsString(results);
-
- reporter.reportAssessmentComplete(user, level, completionDate, data);
-
- } catch (JsonProcessingException e) {
- LOG.error("Failed to generate json " + e.getMessage(), e);
- }
- }
-
- /**
- * @return The backend endpoint URI
- */
- private String getBackendEndpoint() {
- return mConfig.getString("backendUri", "riap://component/backend");
- }
-
- /**
- * Helper method to send a GET to the backend.
- */
- private JsonResponse backendGet(final String uri) {
- LOG.debug("Sending backend GET " + uri);
-
- 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());
- }
-
- return response;
- }
-}
diff --git a/src/com/p4square/grow/frontend/AuthenticatedResource.java b/src/com/p4square/grow/frontend/AuthenticatedResource.java
deleted file mode 100644
index 800eb83..0000000
--- a/src/com/p4square/grow/frontend/AuthenticatedResource.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import org.restlet.resource.ServerResource;
-import org.restlet.representation.Representation;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class AuthenticatedResource extends ServerResource {
- protected Representation post() {
- return null;
- }
-}
diff --git a/src/com/p4square/grow/frontend/ChapterCompletePage.java b/src/com/p4square/grow/frontend/ChapterCompletePage.java
deleted file mode 100644
index 35abc43..0000000
--- a/src/com/p4square/grow/frontend/ChapterCompletePage.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.Date;
-import java.util.Map;
-
-import com.p4square.f1oauth.FellowshipOneIntegrationDriver;
-import freemarker.template.Template;
-
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-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.model.TrainingRecord;
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.TrainingRecordProvider;
-import org.restlet.security.User;
-
-/**
- * This resource displays the transitional page between chapters.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class ChapterCompletePage extends FreeMarkerPageResource {
- private static final Logger LOG = Logger.getLogger(ChapterCompletePage.class);
-
- private GrowFrontend mGrowFrontend;
- private Config mConfig;
- private JsonRequestClient mJsonClient;
- private Provider<String, TrainingRecord> mTrainingRecordProvider;
-
- private String mUserId;
- private String mChapter;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mGrowFrontend = (GrowFrontend) getApplication();
- mConfig = mGrowFrontend.getConfig();
-
- mJsonClient = new JsonRequestClient(getContext().getClientDispatcher());
- mTrainingRecordProvider = new TrainingRecordProvider<String>(
- new JsonRequestProvider<TrainingRecord>(
- getContext().getClientDispatcher(),
- TrainingRecord.class)) {
- @Override
- public String makeKey(String userid) {
- return getBackendEndpoint() + "/accounts/" + userid + "/training";
- }
- };
-
- mUserId = getRequest().getClientInfo().getUser().getIdentifier();
-
- mChapter = getAttribute("chapter");
- }
-
- /**
- * Return the login page.
- */
- @Override
- protected Representation get() {
- try {
- Map<String, Object> root = getRootObject();
-
- // Get the training summary
- TrainingRecord trainingRecord = mTrainingRecordProvider.get(mUserId);
- if (trainingRecord == null) {
- // Wait. What? Everyone has a training record...
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return new ErrorPage("Could not retrieve your training record.");
- }
-
- // Verify they completed the chapter.
- Map<String, Boolean> chapters = trainingRecord.getPlaylist().getChapterStatuses();
- Boolean completed = chapters.get(mChapter);
- if (completed == null || !completed) {
- // Redirect back to training page...
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/account/training/" + mChapter;
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
- }
-
- // Publish the training chapter complete attribute.
- assignAttribute();
-
- // Find the next chapter
- String nextChapter = null;
- {
- int min = Integer.MAX_VALUE;
- for (Map.Entry<String, Boolean> chapter : chapters.entrySet()) {
- int index = chapterIndex(chapter.getKey());
- if (!chapter.getValue() && index < min) {
- min = index;
- nextChapter = chapter.getKey();
- }
- }
- }
-
- String nextOverride = getQueryValue("next");
- if (nextOverride != null) {
- nextChapter = nextOverride;
- }
-
- root.put("stage", mChapter);
- root.put("nextstage", nextChapter);
-
- /*
- * We will display one of two transitional pages:
- *
- * If the next chapter has a forward page, display the forward page.
- * Else, if this chapter is not "Introduction", display the chapter
- * complete message.
- */
- Template t = mGrowFrontend.getTemplate("templates/stage-"
- + nextChapter + "-forward.ftl");
-
- if (t == null) {
- // Skip the chapter complete message for "Introduction"
- if ("introduction".equals(mChapter)) {
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/account/training/" + nextChapter;
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
- }
-
- t = mGrowFrontend.getTemplate("templates/stage-complete.ftl");
- if (t == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return ErrorPage.TEMPLATE_NOT_FOUND;
- }
- }
-
- return new TemplateRepresentation(t, root, MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- private void assignAttribute() {
- final ProgressReporter reporter = mGrowFrontend.getThirdPartyIntegrationFactory().getProgressReporter();
-
- final User user = getRequest().getClientInfo().getUser();
- final Date completionDate = new Date();
-
- reporter.reportChapterComplete(user, mChapter, completionDate);
- }
-
- /**
- * @return The backend endpoint URI
- */
- private String getBackendEndpoint() {
- return mConfig.getString("backendUri", "riap://component/backend");
- }
-
- /**
- * Helper method to send a GET to the backend.
- */
- private JsonResponse backendGet(final String uri) {
- LOG.debug("Sending backend GET " + uri);
-
- 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());
- }
-
- return response;
- }
-
- int chapterIndex(String chapter) {
- if ("leader".equals(chapter)) {
- return 5;
- } else if ("teacher".equals(chapter)) {
- return 4;
- } else if ("disciple".equals(chapter)) {
- return 3;
- } else if ("believer".equals(chapter)) {
- return 2;
- } else if ("seeker".equals(chapter)) {
- return 1;
- } else {
- return Integer.MAX_VALUE;
- }
- }
-}
diff --git a/src/com/p4square/grow/frontend/ErrorPage.java b/src/com/p4square/grow/frontend/ErrorPage.java
deleted file mode 100644
index 81abe74..0000000
--- a/src/com/p4square/grow/frontend/ErrorPage.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import freemarker.template.Template;
-
-import org.restlet.data.MediaType;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.representation.WriterRepresentation;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-/**
- * ErrorPage wraps a String or Template Representation and displays the given
- * error message.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class ErrorPage extends WriterRepresentation {
- public static final ErrorPage TEMPLATE_NOT_FOUND =
- new ErrorPage("Could not find the requested page template.");
-
- public static final ErrorPage RENDER_ERROR =
- new ErrorPage("Error rendering page.");
-
- public static final ErrorPage BACKEND_ERROR =
- new ErrorPage("Error communicating with backend.");
-
- public static final ErrorPage NOT_FOUND =
- new ErrorPage("The requested URL could not be found.");
-
- private static Template cTemplate = null;
- private static Map<String, Object> cRoot = null;
-
- private final String mMessage;
-
- public ErrorPage(String msg) {
- this(msg, MediaType.TEXT_HTML);
- }
-
- public ErrorPage(String msg, MediaType mediaType) {
- super(mediaType);
-
- mMessage = msg;
- }
-
- public static synchronized void setTemplate(Template template, Map<String, Object> root) {
- cTemplate = template;
- cRoot = root;
- }
-
- protected Representation getRepresentation() {
- if (cTemplate == null) {
- return new StringRepresentation(mMessage);
-
- } else {
- Map<String, Object> root = new HashMap<String, Object>(cRoot);
- root.put("errorMessage", mMessage);
- return new TemplateRepresentation(cTemplate, root, MediaType.TEXT_HTML);
- }
- }
-
- @Override
- public void write(Writer writer) throws IOException {
- getRepresentation().write(writer);
- }
-}
diff --git a/src/com/p4square/grow/frontend/FeedData.java b/src/com/p4square/grow/frontend/FeedData.java
deleted file mode 100644
index feb03a1..0000000
--- a/src/com/p4square/grow/frontend/FeedData.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.io.IOException;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
-import org.restlet.Context;
-import org.restlet.Restlet;
-
-import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.type.TypeFactory;
-
-import com.p4square.grow.config.Config;
-import com.p4square.grow.frontend.JsonRequestProvider;
-import com.p4square.grow.model.Message;
-import com.p4square.grow.model.MessageThread;
-import com.p4square.grow.provider.JsonEncodedProvider;
-import com.p4square.grow.provider.Provider;
-
-/**
- * Fetch feed data for a topic.
- */
-public class FeedData {
-
- /**
- * Allowed Topics.
- */
- public static final HashSet<String> TOPICS = new HashSet(Arrays.asList("seeker", "believer",
- "disciple", "teacher", "leader"));
-
-
- private final Config mConfig;
- private final String mBackendURI;
-
- // TODO: Elegantly merge the List and individual providers.
- private final JsonRequestProvider<List<MessageThread>> mThreadsProvider;
- private final JsonRequestProvider<MessageThread> mThreadProvider;
-
- private final JsonRequestProvider<List<Message>> mMessagesProvider;
- private final JsonRequestProvider<Message> mMessageProvider;
-
- public FeedData(final Context context, final Config config) {
- mConfig = config;
- mBackendURI = mConfig.getString("backendUri", "riap://component/backend") + "/feed";
-
- Restlet clientDispatcher = context.getClientDispatcher();
-
- TypeFactory factory = JsonEncodedProvider.MAPPER.getTypeFactory();
-
- JavaType threadType = factory.constructCollectionType(List.class, MessageThread.class);
- mThreadsProvider = new JsonRequestProvider<List<MessageThread>>(clientDispatcher, threadType);
- mThreadProvider = new JsonRequestProvider<MessageThread>(clientDispatcher, MessageThread.class);
-
- JavaType messageType = factory.constructCollectionType(List.class, Message.class);
- mMessagesProvider = new JsonRequestProvider<List<Message>>(clientDispatcher, messageType);
- mMessageProvider = new JsonRequestProvider<Message>(clientDispatcher, Message.class);
- }
-
- /**
- * Get the threads for a topic.
- *
- * @param topic The topic to request threads for.
- * @param limit The maximum number of threads.
- * @return A list of MessageThread objects.
- */
- public List<MessageThread> getThreads(final String topic, final int limit) throws IOException {
- return mThreadsProvider.get(makeUrl(limit, topic));
- }
-
- public List<Message> getMessages(final String topic, final String threadId) throws IOException {
- return mMessagesProvider.get(makeUrl(topic, threadId));
- }
-
- public void createThread(final String topic, final Message message) throws IOException {
- MessageThread thread = new MessageThread();
- thread.setMessage(message);
-
- mThreadProvider.post(makeUrl(topic), thread);
- }
-
- public void createResponse(final String topic, final String thread, final Message message)
- throws IOException {
-
- mMessageProvider.post(makeUrl(topic, thread), message);
- }
-
- private String makeUrl(String... parts) {
- String url = mBackendURI;
- for (String part : parts) {
- url += "/" + part;
- }
-
- return url;
- }
-
- private String makeUrl(int limit, String... parts) {
- return makeUrl(parts) + "?limit=" + limit;
- }
-}
diff --git a/src/com/p4square/grow/frontend/FeedResource.java b/src/com/p4square/grow/frontend/FeedResource.java
deleted file mode 100644
index 13d0fa0..0000000
--- a/src/com/p4square/grow/frontend/FeedResource.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.io.IOException;
-
-import org.restlet.data.Form;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ServerResource;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.grow.config.Config;
-import com.p4square.grow.model.Message;
-import com.p4square.grow.model.UserRecord;
-
-/**
- * This resource handles user interactions with the feed.
- */
-public class FeedResource extends ServerResource {
- private static final Logger LOG = Logger.getLogger(FeedResource.class);
-
- private Config mConfig;
-
- private FeedData mFeedData;
-
- // Fields pertaining to this request.
- protected String mTopic;
- protected String mThread;
-
- @Override
- public void doInit() {
- super.doInit();
-
- GrowFrontend growFrontend = (GrowFrontend) getApplication();
- mConfig = growFrontend.getConfig();
-
- mFeedData = new FeedData(getContext(), mConfig);
-
- mTopic = getAttribute("topic");
- if (mTopic != null) {
- mTopic = mTopic.trim();
- }
-
- mThread = getAttribute("thread");
- if (mThread != null) {
- mThread = mThread.trim();
- }
- }
-
- /**
- * Create a new MessageThread.
- */
- @Override
- protected Representation post(Representation entity) {
- try {
- if (mTopic == null || mTopic.length() == 0 || !FeedData.TOPICS.contains(mTopic)) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return ErrorPage.NOT_FOUND;
- }
-
- Form form = new Form(entity);
-
- String question = form.getFirstValue("question");
-
- Message message = new Message();
- message.setMessage(question);
-
- UserRecord user = new UserRecord(getRequest().getClientInfo().getUser());
- message.setAuthor(user);
-
- if (mThread != null && mThread.length() != 0) {
- // Post a response
- mFeedData.createResponse(mTopic, mThread, message);
-
- } else {
- // Post a new thread
- mFeedData.createThread(mTopic, message);
- }
-
- /*
- * Can't trust the referrer, so we'll send them to the
- * appropriate part of the training page
- * TODO: This could be better done.
- */
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/account/training/" + mTopic;
- getResponse().redirectSeeOther(nextPage);
- return null;
-
- } catch (IOException e) {
- LOG.fatal("Could not save message: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.BACKEND_ERROR;
-
- }
- }
-}
diff --git a/src/com/p4square/grow/frontend/GroupLeaderTrainingPageResource.java b/src/com/p4square/grow/frontend/GroupLeaderTrainingPageResource.java
deleted file mode 100644
index 3ab140e..0000000
--- a/src/com/p4square/grow/frontend/GroupLeaderTrainingPageResource.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-/**
- * Display the Group Leader training videos.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class GroupLeaderTrainingPageResource extends TrainingPageResource {
- private static final String[] CHAPTERS = { "leader" };
-
- @Override
- public void doInit() {
- super.doInit();
-
- mChapter = "leader";
- }
-
- @Override
- public String[] getChaptersInOrder() {
- return CHAPTERS;
- }
-}
diff --git a/src/com/p4square/grow/frontend/GrowFrontend.java b/src/com/p4square/grow/frontend/GrowFrontend.java
deleted file mode 100644
index b5f62fb..0000000
--- a/src/com/p4square/grow/frontend/GrowFrontend.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan <jesse@jesterpm.net>
- */
-
-package com.p4square.grow.frontend;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-
-import freemarker.template.Template;
-
-import org.restlet.Application;
-import org.restlet.Component;
-import org.restlet.Context;
-import org.restlet.Restlet;
-import org.restlet.data.Protocol;
-import org.restlet.resource.Directory;
-import org.restlet.routing.Redirector;
-import org.restlet.routing.Router;
-import org.restlet.security.Authenticator;
-
-import com.codahale.metrics.MetricRegistry;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.FMFacade;
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-import com.p4square.grow.config.Config;
-
-import com.p4square.restlet.metrics.MetricRouter;
-
-import com.p4square.session.SessionCheckingAuthenticator;
-import com.p4square.session.SessionCreatingAuthenticator;
-import org.restlet.security.Verifier;
-
-/**
- * This is the Restlet Application implementing the Grow project front-end.
- * It's implemented as an extension of FMFacade that connects interactive pages
- * with various ServerResources. This class provides a main method to start a
- * Jetty instance for testing.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class GrowFrontend extends FMFacade {
- private static Logger LOG = Logger.getLogger(GrowFrontend.class);
-
- private final Config mConfig;
- private final MetricRegistry mMetricRegistry;
-
- private IntegrationDriver mIntegrationFactory;
-
- public GrowFrontend() {
- this(new Config(), new MetricRegistry());
- }
-
- public GrowFrontend(Config config, MetricRegistry metricRegistry) {
- mConfig = config;
- mMetricRegistry = metricRegistry;
- }
-
- public Config getConfig() {
- return mConfig;
- }
-
- public MetricRegistry getMetrics() {
- return mMetricRegistry;
- }
-
- @Override
- public synchronized void start() throws Exception {
- Template errorTemplate = getTemplate("templates/error.ftl");
- if (errorTemplate != null) {
- ErrorPage.setTemplate(errorTemplate,
- FreeMarkerPageResource.baseRootObject(getContext(), this));
- }
-
- getContext().getAttributes().put("com.p4square.grow.config", mConfig);
- getContext().getAttributes().put("com.p4square.grow.metrics", mMetricRegistry);
-
- super.start();
- }
-
- public synchronized IntegrationDriver getThirdPartyIntegrationFactory() {
- if (mIntegrationFactory == null) {
- final String driverClassName = getConfig().getString("integrationDriver",
- "com.p4square.f1oauth.FellowshipOneIntegrationDriver");
- try {
- Class<?> clazz = Class.forName(driverClassName);
- Constructor<?> constructor = clazz.getConstructor(Context.class);
- mIntegrationFactory = (IntegrationDriver) constructor.newInstance(getContext());
- } catch (Exception e) {
- LOG.error("Failed to instantiate IntegrationDriver " + driverClassName);
- }
- }
-
- return mIntegrationFactory;
- }
-
- @Override
- protected Router createRouter() {
- Router router = new MetricRouter(getContext(), mMetricRegistry);
-
- final Authenticator defaultGuard = new SessionCheckingAuthenticator(getContext(), true);
- defaultGuard.setNext(FreeMarkerPageResource.class);
- router.attachDefault(defaultGuard);
- router.attach("/", new Redirector(getContext(), "index.html", Redirector.MODE_CLIENT_PERMANENT));
- router.attach("/login.html", LoginPageResource.class);
- router.attach("/newaccount.html", NewAccountResource.class);
- router.attach("/newbeliever", NewBelieverResource.class);
-
- final Router accountRouter = new MetricRouter(getContext(), mMetricRegistry);
- accountRouter.attach("/authenticate", AuthenticatedResource.class);
- accountRouter.attach("/logout", LogoutResource.class);
-
- accountRouter.attach("", AccountRedirectResource.class);
- accountRouter.attach("/assessment/question/{questionId}", SurveyPageResource.class);
- accountRouter.attach("/assessment/results", AssessmentResultsPage.class);
- accountRouter.attach("/assessment/reset", AssessmentResetPage.class);
- accountRouter.attach("/assessment", SurveyPageResource.class);
- accountRouter.attach("/training/{chapter}/completed", ChapterCompletePage.class);
- accountRouter.attach("/training/{chapter}/videos/{videoId}.json", VideosResource.class);
- accountRouter.attach("/training/{chapter}", TrainingPageResource.class);
- accountRouter.attach("/training", TrainingPageResource.class);
- accountRouter.attach("/feed/{topic}", FeedResource.class);
- accountRouter.attach("/feed/{topic}/{thread}", FeedResource.class);
-
- final Authenticator accountGuard = createAuthenticatorChain(accountRouter);
- router.attach("/account", accountGuard);
-
- return router;
- }
-
- private Authenticator createAuthenticatorChain(Restlet last) {
- final Context context = getContext();
- final String loginPage = getConfig().getString("dynamicRoot", "") + "/login.html";
- final String loginPost = getConfig().getString("dynamicRoot", "") + "/account/authenticate";
- final String defaultPage = getConfig().getString("dynamicRoot", "") + "/account";
-
- // This is used to check for an existing session
- SessionCheckingAuthenticator sessionChk = new SessionCheckingAuthenticator(context, true);
-
- // This is used to authenticate the user
- Verifier verifier = getThirdPartyIntegrationFactory().newUserAuthenticationVerifier();
- LoginFormAuthenticator loginAuth = new LoginFormAuthenticator(context, false, verifier);
- loginAuth.setLoginFormUrl(loginPage);
- loginAuth.setLoginPostUrl(loginPost);
- loginAuth.setDefaultPage(defaultPage);
-
- // This is used to create a new session for a newly authenticated user.
- SessionCreatingAuthenticator sessionCreate = new SessionCreatingAuthenticator(context);
-
- sessionChk.setNext(loginAuth);
- loginAuth.setNext(sessionCreate);
-
- sessionCreate.setNext(last);
-
- return sessionChk;
- }
-
- /**
- * Stand-alone main for testing.
- */
- public static void main(String[] args) {
- // Start the HTTP Server
- final Component component = new Component();
- component.getServers().add(Protocol.HTTP, 8085);
- component.getClients().add(Protocol.HTTP);
- component.getClients().add(Protocol.HTTPS);
- component.getClients().add(Protocol.FILE);
- //component.getClients().add(new Client(null, Arrays.asList(Protocol.HTTPS), "org.restlet.ext.httpclient.HttpClientHelper"));
-
- // Static content
- try {
- component.getDefaultHost().attach("/images/", new FileServingApp("./build/root/images/"));
- component.getDefaultHost().attach("/scripts", new FileServingApp("./build/root/scripts"));
- component.getDefaultHost().attach("/style.css", new FileServingApp("./build/root/style.css"));
- component.getDefaultHost().attach("/favicon.ico", new FileServingApp("./build/root/favicon.ico"));
- component.getDefaultHost().attach("/notfound.html", new FileServingApp("./build/root/notfound.html"));
- component.getDefaultHost().attach("/error.html", new FileServingApp("./build/root/error.html"));
- } catch (IOException e) {
- LOG.error("Could not create directory for static resources: "
- + e.getMessage(), e);
- }
-
- // Setup App
- GrowFrontend app = new GrowFrontend();
-
- // Load an optional config file from the first argument.
- app.getConfig().setDomain("dev");
- if (args.length == 1) {
- app.getConfig().updateConfig(args[0]);
- }
-
- component.getDefaultHost().attach(app);
-
- // Setup shutdown hook
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void run() {
- try {
- component.stop();
- } catch (Exception e) {
- LOG.error("Exception during cleanup", e);
- }
- }
- });
-
- LOG.info("Starting server...");
-
- try {
- component.start();
- } catch (Exception e) {
- LOG.fatal("Could not start: " + e.getMessage(), e);
- }
- }
-
- private static class FileServingApp extends Application {
- private final String mPath;
-
- public FileServingApp(String path) throws IOException {
- mPath = new File(path).getAbsolutePath();
- }
-
- @Override
- public Restlet createInboundRoot() {
- return new Directory(getContext(), "file://" + mPath);
- }
- }
-}
diff --git a/src/com/p4square/grow/frontend/IntegrationDriver.java b/src/com/p4square/grow/frontend/IntegrationDriver.java
deleted file mode 100644
index b9c3508..0000000
--- a/src/com/p4square/grow/frontend/IntegrationDriver.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.p4square.grow.frontend;
-
-import org.restlet.security.Verifier;
-
-/**
- * An IntegrationDriver is used to create implementations of various objects
- * used to integration Grow with a particular Church Management System.
- */
-public interface IntegrationDriver {
-
- /**
- * Create a new Restlet Verifier to authenticate users when they login to the site.
- *
- * @return A Verifier.
- */
- Verifier newUserAuthenticationVerifier();
-
- /**
- * Return a ProgressReporter for this Church Management System.
- *
- * The ProgressReporter should be thread-safe.
- *
- * @return The ProgressReporter.
- */
- ProgressReporter getProgressReporter();
-}
diff --git a/src/com/p4square/grow/frontend/JsonRequestProvider.java b/src/com/p4square/grow/frontend/JsonRequestProvider.java
deleted file mode 100644
index bf3b2b3..0000000
--- a/src/com/p4square/grow/frontend/JsonRequestProvider.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.databind.JavaType;
-
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.Restlet;
-import org.restlet.data.Method;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- * Fetch a JSON object via a Request.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class JsonRequestProvider<V> extends JsonEncodedProvider<V> implements Provider<String, V> {
-
- private final Restlet mDispatcher;
-
- public JsonRequestProvider(Restlet dispatcher, Class<V> clazz) {
- super(clazz);
-
- mDispatcher = dispatcher;
- }
-
- public JsonRequestProvider(Restlet dispatcher, JavaType type) {
- super(type);
-
- mDispatcher = dispatcher;
- }
-
- @Override
- public V get(String url) throws IOException {
- Request request = new Request(Method.GET, url);
- Response response = mDispatcher.handle(request);
- Representation representation = response.getEntity();
-
- if (!response.getStatus().isSuccess()) {
- if (representation != null) {
- representation.release();
- }
-
- if (Status.CLIENT_ERROR_NOT_FOUND.equals(response.getStatus())) {
- throw new NotFoundException("Could not get object. " + response.getStatus());
- } else {
- throw new IOException("Could not get object. " + response.getStatus());
- }
- }
-
- return decode(representation.getText());
- }
-
- @Override
- public void put(String url, V obj) throws IOException {
- final Request request = new Request(Method.PUT, url);
- request.setEntity(new StringRepresentation(encode(obj)));
-
- final Response response = mDispatcher.handle(request);
-
- if (!response.getStatus().isSuccess()) {
- throw new IOException("Could not put object. " + response.getStatus());
- }
- }
-
- /**
- * Variant of put() which makes a POST request to the url.
- *
- * This method may eventually be incorporated into Provider for
- * creating new objects with auto-generated IDs.
- *
- * @param url The url to make the request to.
- * @param obj The post to post.
- * @throws IOException on failure.
- */
- public void post(String url, V obj) throws IOException {
- final Request request = new Request(Method.POST, url);
- request.setEntity(new StringRepresentation(encode(obj)));
-
- final Response response = mDispatcher.handle(request);
-
- if (!response.getStatus().isSuccess()) {
- throw new IOException("Could not put object. " + response.getStatus());
- }
- }
-}
diff --git a/src/com/p4square/grow/frontend/LoginFormAuthenticator.java b/src/com/p4square/grow/frontend/LoginFormAuthenticator.java
deleted file mode 100644
index 21c9097..0000000
--- a/src/com/p4square/grow/frontend/LoginFormAuthenticator.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.data.ChallengeResponse;
-import org.restlet.data.ChallengeScheme;
-import org.restlet.data.Form;
-import org.restlet.data.Method;
-import org.restlet.data.Reference;
-import org.restlet.security.Authenticator;
-import org.restlet.security.Verifier;
-
-/**
- * LoginFormAuthenticator changes
- *
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class LoginFormAuthenticator extends Authenticator {
- private static final Logger LOG = Logger.getLogger(LoginFormAuthenticator.class);
-
- private final Verifier mVerifier;
-
- private String mLoginPage = "/login.html";
- private String mLoginPostUrl = "/authenticate";
- private String mDefaultRedirect = "/index.html";
-
- public LoginFormAuthenticator(Context context, boolean optional, Verifier verifier) {
- super(context, false, optional, null);
-
- mVerifier = verifier;
- }
-
- public void setLoginFormUrl(String url) {
- mLoginPage = url;
- }
-
- public void setLoginPostUrl(String url) {
- mLoginPostUrl = url;
- }
-
- public void setDefaultPage(String url) {
- mDefaultRedirect = url;
- }
-
- @Override
- protected int beforeHandle(Request request, Response response) {
- if (!isLoginAttempt(request) && request.getClientInfo().isAuthenticated()) {
- // TODO: Logout
- LOG.debug("Already authenticated. Skipping");
- return CONTINUE;
-
- } else {
- return super.beforeHandle(request, response);
- }
- }
-
-
- @Override
- protected boolean authenticate(Request request, Response response) {
- boolean isLoginAttempt = isLoginAttempt(request);
-
- Form query = request.getOriginalRef().getQueryAsForm();
- String redirect = query.getFirstValue("redirect");
- if (redirect == null || redirect.length() == 0) {
- if (isLoginAttempt) {
- redirect = mDefaultRedirect;
- } else {
- redirect = request.getResourceRef().getPath();
- }
- }
-
- boolean authenticationFailed = false;
-
- if (isLoginAttempt) {
- LOG.debug("Attempting authentication");
-
- // Process login form
- final Form form = new Form(request.getEntity());
- final String email = form.getFirstValue("email");
- final String password = form.getFirstValue("password");
-
- boolean authenticated = false;
-
- if (email != null && !"".equals(email) &&
- password != null && !"".equals(password)) {
-
- LOG.debug("Got login request from " + email);
-
- request.setChallengeResponse(
- new ChallengeResponse(ChallengeScheme.HTTP_BASIC, email, password.toCharArray()));
-
- // We expect the verifier to setup the User object.
- int result = mVerifier.verify(request, response);
- if (result == Verifier.RESULT_VALID) {
- return true;
- }
- }
-
- authenticationFailed = true;
- }
-
- if (!isOptional() || authenticationFailed) {
- Reference ref = new Reference(mLoginPage);
- ref.addQueryParameter("redirect", redirect);
-
- if (authenticationFailed) {
- ref.addQueryParameter("retry", "t");
- }
-
- LOG.debug("Redirecting to " + ref);
- response.redirectSeeOther(ref.toString());
- }
- LOG.debug("Failing authentication.");
- return false;
- }
-
- @Override
- protected int authenticated(Request request, Response response) {
- super.authenticated(request, response);
-
- Form query = request.getOriginalRef().getQueryAsForm();
- String redirect = query.getFirstValue("redirect");
- if (redirect == null || redirect.length() == 0) {
- redirect = mDefaultRedirect;
- }
-
- // TODO: Ensure redirect is a relative url.
- LOG.debug("Redirecting to " + redirect);
- response.redirectSeeOther(redirect);
-
- return CONTINUE;
- }
-
- private boolean isLoginAttempt(Request request) {
- String requestPath = request.getResourceRef().getPath();
- return request.getMethod() == Method.POST && mLoginPostUrl.equals(requestPath);
- }
-}
diff --git a/src/com/p4square/grow/frontend/LoginPageResource.java b/src/com/p4square/grow/frontend/LoginPageResource.java
deleted file mode 100644
index 38eba07..0000000
--- a/src/com/p4square/grow/frontend/LoginPageResource.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.Map;
-
-import freemarker.template.Template;
-
-import org.restlet.data.Form;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.resource.ServerResource;
-import org.restlet.representation.Representation;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-/**
- * LoginPageResource presents a login page template and processes the response.
- * Upon successful authentication, the user is redirected to another page and
- * a cookie is set.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class LoginPageResource extends FreeMarkerPageResource {
- private static Logger cLog = Logger.getLogger(LoginPageResource.class);
-
- private GrowFrontend mGrowFrontend;
-
- private String mErrorMessage;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mGrowFrontend = (GrowFrontend) getApplication();
-
- mErrorMessage = null;
- }
-
- /**
- * Return the login page.
- */
- @Override
- protected Representation get() {
- Template t = mGrowFrontend.getTemplate("pages/login.html.ftl");
-
- try {
- if (t == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
-
- Map<String, Object> root = getRootObject();
-
- Form query = getRequest().getOriginalRef().getQueryAsForm();
- String redirect = query.getFirstValue("redirect");
- root.put("redirect", redirect);
- String retry = query.getFirstValue("retry");
- if ("t".equals(retry)) {
- root.put("errorMessage", "Invalid email or password.");
- }
-
- return new TemplateRepresentation(t, root, MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- cLog.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-
-}
diff --git a/src/com/p4square/grow/frontend/LogoutResource.java b/src/com/p4square/grow/frontend/LogoutResource.java
deleted file mode 100644
index e26dcb7..0000000
--- a/src/com/p4square/grow/frontend/LogoutResource.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.resource.ServerResource;
-
-import com.p4square.session.Sessions;
-
-import com.p4square.grow.config.Config;
-
-/**
- * This Resource removes a user's session and session cookies.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class LogoutResource extends ServerResource {
- private Config mConfig;
-
- @Override
- protected void doInit() {
- super.doInit();
-
- GrowFrontend growFrontend = (GrowFrontend) getApplication();
- mConfig = growFrontend.getConfig();
- }
-
- @Override
- protected Representation get() {
- Sessions.getInstance().delete(getRequest(), getResponse());
-
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/index.html";
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
- }
-}
diff --git a/src/com/p4square/grow/frontend/NewAccountResource.java b/src/com/p4square/grow/frontend/NewAccountResource.java
deleted file mode 100644
index 5c13017..0000000
--- a/src/com/p4square/grow/frontend/NewAccountResource.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.Map;
-
-import com.p4square.f1oauth.FellowshipOneIntegrationDriver;
-import freemarker.template.Template;
-
-import org.restlet.data.Form;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.f1oauth.F1Access;
-import com.p4square.restlet.oauth.OAuthException;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-/**
- * This resource creates a new InFellowship account.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class NewAccountResource extends FreeMarkerPageResource {
- private static Logger LOG = Logger.getLogger(NewAccountResource.class);
-
- private GrowFrontend mGrowFrontend;
- private F1Access mHelper;
-
- private String mErrorMessage;
-
- private String mLoginPageUrl;
- private String mVerificationPage;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mGrowFrontend = (GrowFrontend) getApplication();
-
- final IntegrationDriver driver = mGrowFrontend.getThirdPartyIntegrationFactory();
- if (driver instanceof FellowshipOneIntegrationDriver) {
- mHelper = ((FellowshipOneIntegrationDriver) driver).getF1Access();
- } else {
- LOG.error("NewAccountResource only works with F1!");
- mHelper = null;
- }
-
- mErrorMessage = "";
-
- mLoginPageUrl = mGrowFrontend.getConfig().getString("postAccountCreationPage",
- getRequest().getRootRef().toString());
- mVerificationPage = mGrowFrontend.getConfig().getString("dynamicRoot", "")
- + "/verification.html";
- }
-
- /**
- * Return the login page.
- */
- @Override
- protected Representation get() {
- Template t = mGrowFrontend.getTemplate("pages/newaccount.html.ftl");
-
- try {
- if (t == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return ErrorPage.TEMPLATE_NOT_FOUND;
- }
-
- Map<String, Object> root = getRootObject();
- if (mErrorMessage.length() > 0) {
- root.put("errorMessage", mErrorMessage);
- }
-
- return new TemplateRepresentation(t, root, MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- @Override
- protected Representation post(Representation rep) {
- if (mHelper == null) {
- mErrorMessage += "F1 support is not enabled! ";
- return get();
- }
-
- Form form = new Form(rep);
-
- String firstname = form.getFirstValue("firstname");
- String lastname = form.getFirstValue("lastname");
- String email = form.getFirstValue("email");
-
- if (isEmpty(firstname)) {
- mErrorMessage += "First Name is a required field. ";
- }
- if (isEmpty(lastname)) {
- mErrorMessage += "Last Name is a required field. ";
- }
- if (isEmpty(email)) {
- mErrorMessage += "Email is a required field. ";
- }
-
- if (mErrorMessage.length() > 0) {
- return get();
- }
-
- try {
- if (!mHelper.createAccount(firstname, lastname, email, mLoginPageUrl)) {
- mErrorMessage = "An account with that address already exists.";
- return get();
- }
-
- getResponse().redirectSeeOther(mVerificationPage);
- return new StringRepresentation("Redirecting to " + mVerificationPage);
-
- } catch (OAuthException e) {
- return new ErrorPage(e.getStatus().getDescription());
- }
- }
-
- private boolean isEmpty(String s) {
- return s == null || s.trim().length() == 0;
- }
-}
diff --git a/src/com/p4square/grow/frontend/NewBelieverResource.java b/src/com/p4square/grow/frontend/NewBelieverResource.java
deleted file mode 100644
index 8fe078a..0000000
--- a/src/com/p4square/grow/frontend/NewBelieverResource.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import freemarker.template.Template;
-
-import org.restlet.data.CookieSetting;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.representation.Representation;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-/**
- * This resource displays the transitional page between chapters.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class NewBelieverResource extends FreeMarkerPageResource {
- private static final Logger LOG = Logger.getLogger(NewBelieverResource.class);
-
- public static final String COOKIE_NAME = "seeker";
-
- private GrowFrontend mGrowFrontend;
-
- @Override
- public void doInit() {
- super.doInit();
-
- mGrowFrontend = (GrowFrontend) getApplication();
- }
-
- /**
- * Display the New Believer page.
- *
- * The New Believer page creates a cookie to remember the user,
- * explains what's going on, and then asks the user to go to the login
- * page.
- *
- * When the user hits the {@link AccountRedirectResource} the cookie
- * is read and the user is moved ahead to the training section.
- */
- @Override
- protected Representation get() {
- Template t = mGrowFrontend.getTemplate("templates/newbeliever.ftl");
-
- try {
- if (t == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return ErrorPage.TEMPLATE_NOT_FOUND;
- }
-
- // Set the new believer cookie
- CookieSetting cookie = new CookieSetting(COOKIE_NAME, "true");
- cookie.setPath("/");
- getRequest().getCookies().add(cookie);
- getResponse().getCookieSettings().add(cookie);
-
- return new TemplateRepresentation(t, getRootObject(), MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-}
diff --git a/src/com/p4square/grow/frontend/NotFoundException.java b/src/com/p4square/grow/frontend/NotFoundException.java
deleted file mode 100644
index dfa2a4c..0000000
--- a/src/com/p4square/grow/frontend/NotFoundException.java
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.io.IOException;
-
-public class NotFoundException extends IOException {
- public NotFoundException(final String message) {
- super(message);
- }
-}
diff --git a/src/com/p4square/grow/frontend/ProgressReporter.java b/src/com/p4square/grow/frontend/ProgressReporter.java
deleted file mode 100644
index 2f36832..0000000
--- a/src/com/p4square/grow/frontend/ProgressReporter.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.p4square.grow.frontend;
-
-import org.restlet.security.User;
-
-import java.util.Date;
-
-/**
- * A ProgressReporter is used to record a User's progress in a Church Management System.
- */
-public interface ProgressReporter {
-
- /**
- * Report that the User completed the assessment.
- *
- * @param user The user who completed the assessment.
- * @param level The assessment level.
- * @param date The completion date.
- * @param results Result information (e.g. json of the results).
- */
- void reportAssessmentComplete(User user, String level, Date date, String results);
-
- /**
- * Report that the User completed the chapter.
- *
- * @param user The user who completed the chapter.
- * @param chapter The chapter completed.
- * @param date The completion date.
- */
- void reportChapterComplete(User user, String chapter, Date date);
-}
diff --git a/src/com/p4square/grow/frontend/SurveyPageResource.java b/src/com/p4square/grow/frontend/SurveyPageResource.java
deleted file mode 100644
index 3575fe3..0000000
--- a/src/com/p4square/grow/frontend/SurveyPageResource.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.io.IOException;
-
-import java.util.Map;
-import java.util.HashMap;
-
-import freemarker.template.Template;
-
-import org.restlet.data.Form;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.resource.ServerResource;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.json.JsonRequestClient;
-import com.p4square.fmfacade.json.JsonResponse;
-import com.p4square.fmfacade.json.ClientException;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-import com.p4square.grow.config.Config;
-import com.p4square.grow.model.Question;
-import com.p4square.grow.model.UserRecord;
-import com.p4square.grow.provider.DelegateProvider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-import com.p4square.grow.provider.Provider;
-
-/**
- * SurveyPageResource handles rendering the survey and processing user's answers.
- *
- * This resource expects the user to be authenticated and the ClientInfo User object
- * to be populated. Each question is requested from the backend along with the
- * user's previous answer. Each answer is sent to the backend and the user is redirected
- * to the next question. After the last question the user is sent to his results.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SurveyPageResource extends FreeMarkerPageResource {
- private static final Logger LOG = Logger.getLogger(SurveyPageResource.class);
-
- private Config mConfig;
- private Template mSurveyTemplate;
- private JsonRequestClient mJsonClient;
- private Provider<String, Question> mQuestionProvider;
- private Provider<String, UserRecord> mUserRecordProvider;
-
- // Fields pertaining to this request.
- private String mQuestionId;
- private String mUserId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- GrowFrontend growFrontend = (GrowFrontend) getApplication();
- mConfig = growFrontend.getConfig();
- mSurveyTemplate = growFrontend.getTemplate("templates/survey.ftl");
- if (mSurveyTemplate == null) {
- LOG.fatal("Could not find survey template.");
- setStatus(Status.SERVER_ERROR_INTERNAL);
- }
-
- mJsonClient = new JsonRequestClient(getContext().getClientDispatcher());
- mQuestionProvider = new DelegateProvider<String, String, Question>(
- new JsonRequestProvider<Question>(getContext().getClientDispatcher(),
- Question.class)) {
- @Override
- public String makeKey(String questionId) {
- return getBackendEndpoint() + "/assessment/question/" + questionId;
- }
- };
-
- mUserRecordProvider = new DelegateProvider<String, String, UserRecord>(
- new JsonRequestProvider<UserRecord>(getContext().getClientDispatcher(),
- UserRecord.class)) {
- @Override
- public String makeKey(String userid) {
- return getBackendEndpoint() + "/accounts/" + userid;
- }
- };
-
- mQuestionId = getAttribute("questionId");
- mUserId = getRequest().getClientInfo().getUser().getIdentifier();
- }
-
- /**
- * Return a page with a survey question.
- */
- @Override
- protected Representation get() {
- try {
- // Get the current question.
- if (mQuestionId == null) {
- // Get user's current question
- mQuestionId = getCurrentQuestionId();
-
- if (mQuestionId != null) {
- Question lastQuestion = getQuestion(mQuestionId);
- return redirectToNextQuestion(lastQuestion, getAnswer(mQuestionId));
- }
- }
-
- // If we don't have a current question, get the first one.
- if (mQuestionId == null) {
- mQuestionId = "first";
- }
-
- Question question = getQuestion(mQuestionId);
- if (question == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return new ErrorPage("Could not find the question.");
- }
-
- // Set the real question id if a meta-id was used (i.e. first)
- mQuestionId = question.getId();
-
- // Get any previous answer to the question
- String selectedAnswer = getAnswer(mQuestionId);
-
- Map root = getRootObject();
- root.put("question", question);
- root.put("selectedAnswerId", selectedAnswer);
-
- // Get the question count and compute progress
- {
- JsonResponse response = backendGet("/assessment/question/count");
- if (response.getStatus().isSuccess()) {
- Map countData = response.getMap();
- if (countData != null) {
- response = backendGet("/accounts/" + mUserId + "/assessment");
- if (response.getStatus().isSuccess()) {
- Integer completed = (Integer) response.getMap().get("totalAnswers");
- Integer total = (Integer) countData.get("count");
-
- if (completed != null && total != null && total != 0) {
- root.put("percentComplete", String.valueOf((int) (100.0 * completed) / total));
- }
- }
- }
- }
- }
-
- return new TemplateRepresentation(mSurveyTemplate, root, MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- /**
- * Record a survey answer and redirect to the next question.
- */
- @Override
- protected Representation post(Representation entity) {
- final Form form = new Form(entity);
- final String answerId = form.getFirstValue("answer");
- final String direction = form.getFirstValue("direction");
- boolean justGoBack = false; // FIXME: Ugly hack
-
- if (mQuestionId == null || answerId == null || answerId.length() == 0) {
- if ("previous".equals(direction)) {
- // Just go back
- justGoBack = true;
-
- } else {
- // Something is wrong.
- setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
- return new ErrorPage("Question or answer messing.");
- }
- }
-
- try {
- // Find the question
- Question question = getQuestion(mQuestionId);
- if (question == null) {
- // User is answering a question which doesn't exist
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return new ErrorPage("Question not found.");
- }
-
- // Store answer
- if (!justGoBack) {
- Map<String, String> answer = new HashMap<String, String>();
- answer.put("answerId", answerId);
- JsonResponse response = backendPut("/accounts/" + mUserId +
- "/assessment/answers/" + mQuestionId, answer);
-
- if (!response.getStatus().isSuccess()) {
- // Something went wrong talking to the backend, error out.
- LOG.fatal("Error recording survey answer " + response.getStatus());
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.BACKEND_ERROR;
- }
- }
-
- // Find the next question or finish the assessment.
- if ("previous".equals(direction)) {
- return redirectToPreviousQuestion(question);
-
- } else {
- return redirectToNextQuestion(question, answerId);
- }
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- private Question getQuestion(String id) {
- try {
- return mQuestionProvider.get(id);
-
- } catch (IOException e) {
- LOG.warn("Error fetching question.", e);
- return null;
- }
- }
-
- private String getAnswer(String questionId) {
- try {
- JsonResponse response = backendGet("/accounts/" + mUserId + "/assessment/answers/" + questionId);
- if (response.getStatus().isSuccess()) {
- return (String) response.getMap().get("answerId");
- }
-
- } catch (ClientException e) {
- LOG.warn("Error fetching answer to question " + questionId, e);
- }
-
- return null;
- }
-
- private Representation redirectToNextQuestion(Question question, String answerid) {
- String nextQuestionId = question.getNextQuestion(answerid);
-
- if (nextQuestionId == null) {
- // Just finished the last question. Update the user's account
- try {
- UserRecord account = null;
- try {
- account = mUserRecordProvider.get(mUserId);
- } catch (NotFoundException e) {
- // User record doesn't exist, so create a new one.
- account = new UserRecord(getRequest().getClientInfo().getUser());
- }
- account.setLanding("training");
- mUserRecordProvider.put(mUserId, account);
- } catch (IOException e) {
- LOG.warn("IOException updating landing for " + mUserId, e);
- }
-
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/account/assessment/results";
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
- }
-
- return redirectToQuestion(nextQuestionId);
- }
-
- private Representation redirectToPreviousQuestion(Question question) {
- String nextQuestionId = question.getPreviousQuestion();
-
- if (nextQuestionId == null) {
- nextQuestionId = (String) question.getId();
- }
-
- return redirectToQuestion(nextQuestionId);
- }
-
- private Representation redirectToQuestion(String id) {
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/account/assessment/question/" + id;
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
- }
-
- private String getCurrentQuestionId() {
- String id = null;
- try {
- JsonResponse response = backendGet("/accounts/" + mUserId + "/assessment");
-
- if (response.getStatus().isSuccess()) {
- return (String) response.getMap().get("lastAnswered");
-
- } else {
- LOG.warn("Failed to get assessment results: " + response.getStatus());
- }
-
- } catch (ClientException e) {
- LOG.error("Exception getting assessment results.", e);
- }
-
- return null;
- }
-
- /**
- * @return The backend endpoint URI
- */
- private String getBackendEndpoint() {
- return mConfig.getString("backendUri", "riap://component/backend");
- }
-
- /**
- * Helper method to send a GET to the backend.
- */
- private JsonResponse backendGet(final String uri) {
- LOG.debug("Sending backend GET " + uri);
-
- 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());
- }
-
- return response;
- }
-
- protected JsonResponse backendPut(final String uri, final Map data) {
- LOG.debug("Sending backend PUT " + uri);
-
- final JsonResponse response = mJsonClient.put(getBackendEndpoint() + uri, data);
- 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());
- }
-
- return response;
- }
-}
diff --git a/src/com/p4square/grow/frontend/TrainingPageResource.java b/src/com/p4square/grow/frontend/TrainingPageResource.java
deleted file mode 100644
index a1e7789..0000000
--- a/src/com/p4square/grow/frontend/TrainingPageResource.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import freemarker.template.Template;
-
-import org.restlet.data.CookieSetting;
-import org.restlet.data.Form;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.freemarker.TemplateRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.representation.StringRepresentation;
-import org.restlet.resource.ServerResource;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.json.JsonRequestClient;
-import com.p4square.fmfacade.json.JsonResponse;
-
-import com.p4square.fmfacade.FreeMarkerPageResource;
-
-import com.p4square.grow.config.Config;
-import com.p4square.grow.model.TrainingRecord;
-import com.p4square.grow.model.VideoRecord;
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.provider.TrainingRecordProvider;
-import com.p4square.grow.provider.Provider;
-
-/**
- * TrainingPageResource handles rendering the training page.
- *
- * This resource expects the user to be authenticated and the ClientInfo User object
- * to be populated.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class TrainingPageResource extends FreeMarkerPageResource {
- private static final Logger LOG = Logger.getLogger(TrainingPageResource.class);
-
- private static final String[] CHAPTERS = { "introduction", "seeker", "believer", "disciple", "teacher", "leader" };
- private static final Comparator<Map<String, Object>> VIDEO_COMPARATOR = new Comparator<Map<String, Object>>() {
- @Override
- public int compare(Map<String, Object> left, Map<String, Object> right) {
- String leftNumberStr = (String) left.get("number");
- String rightNumberStr = (String) right.get("number");
-
- if (leftNumberStr == null || rightNumberStr == null) {
- return -1;
- }
-
- double leftNumber = Double.valueOf(leftNumberStr);
- double rightNumber = Double.valueOf(rightNumberStr);
-
- return Double.compare(leftNumber, rightNumber);
- }
- };
-
- private Config mConfig;
- private Template mTrainingTemplate;
- private JsonRequestClient mJsonClient;
-
- private Provider<String, TrainingRecord> mTrainingRecordProvider;
- private FeedData mFeedData;
-
- // Fields pertaining to this request.
- protected String mChapter;
- protected String mUserId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- GrowFrontend growFrontend = (GrowFrontend) getApplication();
- mConfig = growFrontend.getConfig();
- mTrainingTemplate = growFrontend.getTemplate("templates/training.ftl");
- if (mTrainingTemplate == null) {
- LOG.fatal("Could not find training template.");
- setStatus(Status.SERVER_ERROR_INTERNAL);
- }
-
- mJsonClient = new JsonRequestClient(getContext().getClientDispatcher());
- mTrainingRecordProvider = new TrainingRecordProvider<String>(new JsonRequestProvider<TrainingRecord>(getContext().getClientDispatcher(), TrainingRecord.class)) {
- @Override
- public String makeKey(String userid) {
- return getBackendEndpoint() + "/accounts/" + userid + "/training";
- }
- };
-
- mFeedData = new FeedData(getContext(), mConfig);
-
- mChapter = getAttribute("chapter");
- mUserId = getRequest().getClientInfo().getUser().getIdentifier();
- }
-
- /**
- * Return a page of videos.
- */
- @Override
- protected Representation get() {
- try {
- // Get the training summary
- TrainingRecord trainingRecord = mTrainingRecordProvider.get(mUserId);
- if (trainingRecord == null) {
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return new ErrorPage("Could not retrieve TrainingRecord.");
- }
-
- Playlist playlist = trainingRecord.getPlaylist();
- Map<String, Boolean> chapters = playlist.getChapterStatuses();
- Map<String, Boolean> allowedChapters = new LinkedHashMap<String, Boolean>();
-
- // The user is not allowed to view chapters after his highest completed chapter.
- // In this loop we find which chapters are allowed and check if the user tried
- // to skip ahead.
- boolean allowUserToSkip = mConfig.getBoolean("allowUserToSkip", false) || getQueryValue("magicskip") != null;
- String defaultChapter = null;
- boolean userTriedToSkip = false;
- int overallProgress = 0;
-
- boolean foundRequired = false;
- for (String chapterId : getChaptersInOrder()) {
- boolean allowed = true;
-
- Boolean completed = chapters.get(chapterId);
- if (completed != null) {
- if (!foundRequired) {
- if (!completed) {
- // The first incomplete chapter is the highest allowed chapter.
- foundRequired = true;
- defaultChapter = chapterId;
- }
-
- } else {
- allowed = allowUserToSkip;
-
- if (!allowUserToSkip && chapterId.equals(mChapter)) {
- userTriedToSkip = true;
- }
- }
-
- allowedChapters.put(chapterId, allowed);
-
- if (completed) {
- overallProgress++;
- }
- }
- }
-
- // Overall progress is the percentage of chapters complete
- overallProgress = (int) ((double) overallProgress / getChaptersInOrder().length * 100);
-
- if (defaultChapter == null) {
- // Everything is completed... send them back to introduction.
- defaultChapter = "introduction";
- }
-
- if (mChapter == null || userTriedToSkip) {
- // No chapter was specified or the user tried to skip ahead.
- // Either case, redirect.
- String nextPage = mConfig.getString("dynamicRoot", "");
- nextPage += "/account/training/" + defaultChapter;
- getResponse().redirectSeeOther(nextPage);
- return new StringRepresentation("Redirecting to " + nextPage);
- }
-
-
- // Get videos for the chapter.
- List<Map<String, Object>> videos = null;
- {
- JsonResponse response = backendGet("/training/" + mChapter);
- if (!response.getStatus().isSuccess()) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
- return null;
- }
- videos = (List<Map<String, Object>>) response.getMap().get("videos");
- Collections.sort(videos, VIDEO_COMPARATOR);
- }
-
- // Mark the completed videos as completed
- int chapterProgress = 0;
- for (Map<String, Object> video : videos) {
- boolean completed = false;
- VideoRecord record = playlist.find((String) video.get("id"));
- LOG.info("VideoId: " + video.get("id"));
- if (record != null) {
- LOG.info("VideoRecord: " + record.getComplete());
- completed = record.getComplete();
- }
- video.put("completed", completed);
-
- if (completed) {
- chapterProgress++;
- }
- }
- chapterProgress = chapterProgress * 100 / videos.size();
-
- Map root = getRootObject();
- root.put("chapter", mChapter);
- root.put("chapters", allowedChapters.keySet());
- root.put("isChapterAllowed", allowedChapters);
- root.put("chapterProgress", chapterProgress);
- root.put("overallProgress", overallProgress);
- root.put("videos", videos);
- root.put("allowUserToSkip", allowUserToSkip);
-
- // Determine if we should show the feed.
- boolean showfeed = true;
-
- // Don't show the feed if the topic isn't allowed.
- if (!FeedData.TOPICS.contains(mChapter)) {
- showfeed = false;
- }
-
- root.put("showfeed", showfeed);
- if (showfeed) {
- root.put("feeddata", mFeedData);
- }
-
- return new TemplateRepresentation(mTrainingTemplate, root, MediaType.TEXT_HTML);
-
- } catch (Exception e) {
- LOG.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.RENDER_ERROR;
- }
- }
-
- /**
- * This method returns a list of chapters in the correct order.
- */
- protected String[] getChaptersInOrder() {
- return CHAPTERS;
- }
-
- /**
- * @return The backend endpoint URI
- */
- private String getBackendEndpoint() {
- return mConfig.getString("backendUri", "riap://component/backend");
- }
-
- /**
- * Helper method to send a GET to the backend.
- */
- private JsonResponse backendGet(final String uri) {
- LOG.debug("Sending backend GET " + uri);
-
- 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());
- }
-
- return response;
- }
-
-}
diff --git a/src/com/p4square/grow/frontend/VideosResource.java b/src/com/p4square/grow/frontend/VideosResource.java
deleted file mode 100644
index 2099a77..0000000
--- a/src/com/p4square/grow/frontend/VideosResource.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.frontend;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import freemarker.template.Template;
-
-import org.restlet.data.Form;
-import org.restlet.data.MediaType;
-import org.restlet.data.Status;
-import org.restlet.ext.jackson.JacksonRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ServerResource;
-
-import org.apache.log4j.Logger;
-
-import com.p4square.fmfacade.json.JsonRequestClient;
-import com.p4square.fmfacade.json.JsonResponse;
-
-import com.p4square.grow.config.Config;
-
-/**
- * VideosResource returns JSON blobs with video information and records watched
- * videos.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class VideosResource extends ServerResource {
- private static Logger cLog = Logger.getLogger(VideosResource.class);
-
- private Config mConfig;
- private JsonRequestClient mJsonClient;
-
- // Fields pertaining to this request.
- private String mChapter;
- private String mVideoId;
- private String mUserId;
-
- @Override
- public void doInit() {
- super.doInit();
-
- GrowFrontend growFrontend = (GrowFrontend) getApplication();
- mConfig = growFrontend.getConfig();
-
- mJsonClient = new JsonRequestClient(getContext().getClientDispatcher());
-
- mChapter = getAttribute("chapter");
- mVideoId = getAttribute("videoId");
- mUserId = getRequest().getClientInfo().getUser().getIdentifier();
- }
-
- /**
- * Fetch a video record from the backend.
- */
- @Override
- protected Representation get() {
- try {
- JsonResponse response = backendGet("/training/" + mChapter + "/videos/" + mVideoId);
-
- if (response.getStatus().isSuccess()) {
- return new JacksonRepresentation<Map>(response.getMap());
-
- } else {
- setStatus(response.getStatus());
- return null;
- }
-
- } catch (Exception e) {
- cLog.fatal("Could not render page: " + e.getMessage(), e);
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return null;
- }
- }
-
- /**
- * Mark a video as completed.
- */
- @Override
- protected Representation post(Representation entity) {
- Map<String, Object> data = new HashMap<String, Object>();
- data.put("complete", "true");
- JsonResponse response = backendPut("/accounts/" + mUserId + "/training/videos/" + mVideoId, data);
-
- if (!response.getStatus().isSuccess()) {
- // Something went wrong talking to the backend, error out.
- cLog.fatal("Error recording completed video " + response.getStatus());
- setStatus(Status.SERVER_ERROR_INTERNAL);
- return ErrorPage.BACKEND_ERROR;
- }
-
- setStatus(Status.SUCCESS_NO_CONTENT);
- return null;
- }
-
- /**
- * @return The backend endpoint URI
- */
- private String getBackendEndpoint() {
- return mConfig.getString("backendUri", "riap://component/backend");
- }
-
- /**
- * Helper method to send a GET to the backend.
- */
- private JsonResponse backendGet(final String uri) {
- cLog.debug("Sending backend GET " + uri);
-
- final JsonResponse response = mJsonClient.get(getBackendEndpoint() + uri);
- final Status status = response.getStatus();
- if (!status.isSuccess() && !Status.CLIENT_ERROR_NOT_FOUND.equals(status)) {
- cLog.warn("Error making backend request for '" + uri + "'. status = " + response.getStatus().toString());
- }
-
- return response;
- }
-
- private JsonResponse backendPut(final String uri, final Map data) {
- cLog.debug("Sending backend PUT " + uri);
-
- final JsonResponse response = mJsonClient.put(getBackendEndpoint() + uri, data);
- final Status status = response.getStatus();
- if (!status.isSuccess() && !Status.CLIENT_ERROR_NOT_FOUND.equals(status)) {
- cLog.warn("Error making backend request for '" + uri + "'. status = " + response.getStatus().toString());
- }
-
- return response;
- }
-}
diff --git a/src/com/p4square/grow/model/Answer.java b/src/com/p4square/grow/model/Answer.java
deleted file mode 100644
index a818365..0000000
--- a/src/com/p4square/grow/model/Answer.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import org.apache.log4j.Logger;
-
-/**
- * This is the model of an assessment question's answer.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Answer {
- private static final Logger LOG = Logger.getLogger(Answer.class);
-
- /**
- * ScoreType determines how the answer will be scored.
- *
- */
- public static enum ScoreType {
- /**
- * This question has no effect on the score.
- */
- NONE,
-
- /**
- * The score of this question is part of the average.
- */
- AVERAGE,
-
- /**
- * The score of this question is the total score, no other questions
- * matter after this point.
- */
- TRUMP;
-
- @Override
- public String toString() {
- return name().toLowerCase();
- }
- }
-
- private String mAnswerText;
- private ScoreType mType;
- private float mScoreFactor;
- private String mNextQuestionId;
-
- public Answer() {
- mType = ScoreType.AVERAGE;
- }
-
- /**
- * @return The text associated with the answer.
- */
- public String getText() {
- return mAnswerText;
- }
-
- /**
- * Set the text associated with the answer.
- * @param text The new text.
- */
- public void setText(String text) {
- mAnswerText = text;
- }
-
- /**
- * @return the ScoreType for the Answer.
- */
- public ScoreType getType() {
- return mType;
- }
-
- /**
- * Set the ScoreType for the answer.
- * @param type The new ScoreType.
- */
- public void setType(ScoreType type) {
- mType = type;
- }
-
- /**
- * @return the delta of the score if this answer is selected.
- */
- public float getScore() {
- if (mType == ScoreType.NONE) {
- return 0;
- }
-
- return mScoreFactor;
- }
-
- /**
- * Set the score delta for this answer.
- * @param score The new delta.
- */
- public void setScore(float score) {
- mScoreFactor = score;
- }
-
- /**
- * @return the id of the next question if this answer is selected, or null
- * if selecting this answer has no effect.
- */
- public String getNextQuestion() {
- return mNextQuestionId;
- }
-
- /**
- * Set the id of the next question when this answer is selected.
- * @param id The next question id or null to proceed as usual.
- */
- public void setNextQuestion(String id) {
- mNextQuestionId = id;
- }
-
- /**
- * Adjust the running score for the selection of this answer.
- * @param score The running score to adjust.
- * @return true if scoring should continue, false if this answer trumps all.
- */
- public boolean score(final Score score) {
- switch (getType()) {
- case TRUMP:
- score.sum = getScore();
- score.count = 1;
- return false; // Quit scoring.
-
- case AVERAGE:
- LOG.debug("ScoreType.AVERAGE: { delta: \"" + getScore() + "\" }");
- score.sum += getScore();
- score.count++;
- break;
-
- case NONE:
- break;
- }
-
- return true; // Continue scoring
- }
-}
diff --git a/src/com/p4square/grow/model/Banner.java b/src/com/p4square/grow/model/Banner.java
deleted file mode 100644
index b786b36..0000000
--- a/src/com/p4square/grow/model/Banner.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Page Banner Data.
- */
-public class Banner {
- private String mHtml;
-
- public String getHtml() {
- return mHtml;
- }
-
- public void setHtml(final String html) {
- mHtml = html;
- }
-}
diff --git a/src/com/p4square/grow/model/Chapter.java b/src/com/p4square/grow/model/Chapter.java
deleted file mode 100644
index 3a08e4c..0000000
--- a/src/com/p4square/grow/model/Chapter.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonAnySetter;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-
-/**
- * Chapter is a list of VideoRecords in a Playlist.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Chapter implements Cloneable {
- private String mName;
- private Map<String, VideoRecord> mVideos;
-
- public Chapter(String name) {
- mName = name;
- mVideos = new HashMap<String, VideoRecord>();
- }
-
- /**
- * Private constructor for JSON decoding.
- */
- private Chapter() {
- this(null);
- }
-
- /**
- * @return The Chapter name.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Set the chapter name.
- *
- * @param name The name of the chapter.
- */
- public void setName(final String name) {
- mName = name;
- }
-
- /**
- * @return The VideoRecord for videoid or null if videoid is not in the chapter.
- */
- public VideoRecord getVideoRecord(String videoid) {
- return mVideos.get(videoid);
- }
-
- /**
- * @return A map of video ids to VideoRecords.
- */
- @JsonAnyGetter
- public Map<String, VideoRecord> getVideos() {
- return mVideos;
- }
-
- /**
- * Set the VideoRecord for a video id.
- * @param videoId the video id.
- * @param video the VideoRecord.
- */
- @JsonAnySetter
- public void setVideoRecord(String videoId, VideoRecord video) {
- mVideos.put(videoId, video);
- }
-
- /**
- * Remove the VideoRecord for a video id.
- * @param videoId The id to remove.
- */
- public void removeVideoRecord(String videoId) {
- mVideos.remove(videoId);
- }
-
- /**
- * @return true if every required video has been completed.
- */
- @JsonIgnore
- public boolean isComplete() {
- boolean complete = true;
-
- for (VideoRecord r : mVideos.values()) {
- if (r.getRequired() && !r.getComplete()) {
- return false;
- }
- }
-
- return complete;
- }
-
- /**
- * Deeply clone a chapter.
- *
- * @return a new Chapter object identical but independent of this one.
- */
- public Chapter clone() throws CloneNotSupportedException {
- Chapter c = new Chapter(mName);
- for (Map.Entry<String, VideoRecord> videoEntry : mVideos.entrySet()) {
- c.setVideoRecord(videoEntry.getKey(), videoEntry.getValue().clone());
- }
- return c;
- }
-}
diff --git a/src/com/p4square/grow/model/CircleQuestion.java b/src/com/p4square/grow/model/CircleQuestion.java
deleted file mode 100644
index 71acc14..0000000
--- a/src/com/p4square/grow/model/CircleQuestion.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Circle Question.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class CircleQuestion extends Question {
- private static final ScoringEngine ENGINE = new QuadScoringEngine();
-
- private String mTopLeft;
- private String mTopRight;
- private String mBottomLeft;
- private String mBottomRight;
-
- /**
- * @return the Top Left label.
- */
- public String getTopLeft() {
- return mTopLeft;
- }
-
- /**
- * Set the Top Left label.
- * @param s The new top left label.
- */
- public void setTopLeft(String s) {
- mTopLeft = s;
- }
-
- /**
- * @return the Top Right label.
- */
- public String getTopRight() {
- return mTopRight;
- }
-
- /**
- * Set the Top Right label.
- * @param s The new top left label.
- */
- public void setTopRight(String s) {
- mTopRight = s;
- }
-
- /**
- * @return the Bottom Left label.
- */
- public String getBottomLeft() {
- return mBottomLeft;
- }
-
- /**
- * Set the Bottom Left label.
- * @param s The new top left label.
- */
- public void setBottomLeft(String s) {
- mBottomLeft = s;
- }
-
- /**
- * @return the Bottom Right label.
- */
- public String getBottomRight() {
- return mBottomRight;
- }
-
- /**
- * Set the Bottom Right label.
- * @param s The new top left label.
- */
- public void setBottomRight(String s) {
- mBottomRight = s;
- }
-
- @Override
- public boolean scoreAnswer(Score score, RecordedAnswer answer) {
- return ENGINE.scoreAnswer(score, this, answer);
- }
-
- @Override
- public QuestionType getType() {
- return QuestionType.CIRCLE;
- }
-}
diff --git a/src/com/p4square/grow/model/ImageQuestion.java b/src/com/p4square/grow/model/ImageQuestion.java
deleted file mode 100644
index d94c32c..0000000
--- a/src/com/p4square/grow/model/ImageQuestion.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Image Question.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class ImageQuestion extends Question {
- private static final ScoringEngine ENGINE = new SimpleScoringEngine();
-
- @Override
- public boolean scoreAnswer(Score score, RecordedAnswer answer) {
- return ENGINE.scoreAnswer(score, this, answer);
- }
-
- @Override
- public QuestionType getType() {
- return QuestionType.IMAGE;
- }
-}
diff --git a/src/com/p4square/grow/model/Message.java b/src/com/p4square/grow/model/Message.java
deleted file mode 100644
index 9d33320..0000000
--- a/src/com/p4square/grow/model/Message.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import java.util.Date;
-import java.util.UUID;
-
-/**
- * A feed message.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Message {
- private String mThreadId;
- private String mId;
- private UserRecord mAuthor;
- private Date mCreated;
- private String mMessage;
-
- /**
- * @return a new message id.
- */
- public static String generateId() {
- return String.format("%x-%s", System.currentTimeMillis(), UUID.randomUUID().toString());
- }
-
- /**
- * @return The id of the thread that the message belongs to.
- */
- public String getThreadId() {
- return mThreadId;
- }
-
- /**
- * Set the id of the thread that the message belongs to.
- * @param id The new thread id.
- */
- public void setThreadId(String id) {
- mThreadId = id;
- }
-
- /**
- * @return The id the message.
- */
- public String getId() {
- return mId;
- }
-
- /**
- * Set the id of the message.
- * @param id The new message id.
- */
- public void setId(String id) {
- mId = id;
- }
-
- /**
- * @return The author of the message.
- */
- public UserRecord getAuthor() {
- return mAuthor;
- }
-
- /**
- * Set the author of the message.
- * @param author The new author.
- */
- public void setAuthor(UserRecord author) {
- mAuthor = author;
- }
-
- /**
- * @return The Date the message was created.
- */
- public Date getCreated() {
- return mCreated;
- }
-
- /**
- * Set the Date the message was created.
- * @param date The new creation date.
- */
- public void setCreated(Date date) {
- mCreated = date;
- }
-
- /**
- * @return The message text.
- */
- public String getMessage() {
- return mMessage;
- }
-
- /**
- * Set the message text.
- * @param text The message text.
- */
- public void setMessage(String text) {
- mMessage = text;
- }
-}
diff --git a/src/com/p4square/grow/model/MessageThread.java b/src/com/p4square/grow/model/MessageThread.java
deleted file mode 100644
index 9542a18..0000000
--- a/src/com/p4square/grow/model/MessageThread.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import java.util.UUID;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class MessageThread {
- private String mId;
- private Message mMessage;
-
- /**
- * Create a new thread with a probably unique id.
- *
- * @return the new thread.
- */
- public static MessageThread createNew() {
- MessageThread t = new MessageThread();
- // IDs are keyed to sort lexicographically from latest to oldest.
- t.setId(String.format("%016x-%s", Long.MAX_VALUE - System.currentTimeMillis(),
- UUID.randomUUID().toString()));
-
- return t;
- }
-
- /**
- * @return The id the message.
- */
- public String getId() {
- return mId;
- }
-
- /**
- * Set the id of the message.
- * @param id The new message id.
- */
- public void setId(String id) {
- mId = id;
- }
-
- /**
- * @return The original message.
- */
- public Message getMessage() {
- return mMessage;
- }
-
- /**
- * Set the original message.
- * @param id The new message.
- */
- public void setMessage(Message message) {
- mMessage = message;
- }
-}
diff --git a/src/com/p4square/grow/model/Playlist.java b/src/com/p4square/grow/model/Playlist.java
deleted file mode 100644
index 3e77ada..0000000
--- a/src/com/p4square/grow/model/Playlist.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonAnySetter;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-
-/**
- * Representation of a user's playlist.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Playlist {
- /**
- * Map of Chapter ID to map of Video ID to VideoRecord.
- */
- private Map<String, Chapter> mPlaylist;
-
- private Date mLastUpdated;
-
- /**
- * Construct an empty playlist.
- */
- public Playlist() {
- mPlaylist = new HashMap<String, Chapter>();
- mLastUpdated = new Date(0); // Default to a prehistoric date if we don't have one.
- }
-
- /**
- * Find the VideoRecord for a video id.
- */
- public VideoRecord find(String videoId) {
- for (Chapter chapter : mPlaylist.values()) {
- VideoRecord r = chapter.getVideoRecord(videoId);
-
- if (r != null) {
- return r;
- }
- }
-
- return null;
- }
-
- /**
- * @param videoId The video to search for.
- * @return the Chapter containing videoId.
- */
- private Chapter findChapter(String videoId) {
- for (Chapter chapter : mPlaylist.values()) {
- VideoRecord r = chapter.getVideoRecord(videoId);
-
- if (r != null) {
- return chapter;
- }
- }
-
- return null;
- }
-
- /**
- * @return The last modified date of the source playlist.
- */
- public Date getLastUpdated() {
- return mLastUpdated;
- }
-
- /**
- * Set the last updated date.
- * @param date the new last updated date.
- */
- public void setLastUpdated(Date date) {
- mLastUpdated = date;
- }
-
- /**
- * Add a video to the playlist.
- */
- public VideoRecord add(String chapterId, String videoId) {
- Chapter chapter = mPlaylist.get(chapterId);
-
- if (chapter == null) {
- chapter = new Chapter(chapterId);
- mPlaylist.put(chapterId, chapter);
- }
-
- VideoRecord r = new VideoRecord();
- chapter.setVideoRecord(videoId, r);
- return r;
- }
-
- /**
- * Add a Chapter to the Playlist.
- * @param chapterId The name of the chapter.
- * @param chapter The Chapter object to add.
- */
- @JsonAnySetter
- public void addChapter(String chapterId, Chapter chapter) {
- chapter.setName(chapterId);
- mPlaylist.put(chapterId, chapter);
- }
-
- /**
- * @return a map of chapter id to chapter.
- */
- @JsonAnyGetter
- public Map<String, Chapter> getChaptersMap() {
- return mPlaylist;
- }
-
- /**
- * @return The last chapter to be completed.
- */
- @JsonIgnore
- public Map<String, Boolean> getChapterStatuses() {
- Map<String, Boolean> completed = new HashMap<String, Boolean>();
-
- for (Map.Entry<String, Chapter> entry : mPlaylist.entrySet()) {
- completed.put(entry.getKey(), entry.getValue().isComplete());
- }
-
- return completed;
- }
-
- /**
- * @return true if all required videos in the chapter have been watched.
- */
- public boolean isChapterComplete(String chapterId) {
- Chapter chapter = mPlaylist.get(chapterId);
- if (chapter != null) {
- return chapter.isComplete();
- }
-
- return false;
- }
-
- /**
- * Merge a playlist into this playlist.
- *
- * Merge is accomplished by adding all missing Chapters and VideoRecords to
- * this playlist.
- */
- public void merge(Playlist source) {
- if (source.getLastUpdated().before(mLastUpdated)) {
- // Already up to date.
- return;
- }
-
- for (Map.Entry<String, Chapter> entry : source.getChaptersMap().entrySet()) {
- String chapterName = entry.getKey();
- Chapter theirChapter = entry.getValue();
- Chapter myChapter = mPlaylist.get(entry.getKey());
-
- if (myChapter == null) {
- // Add new chapter
- myChapter = new Chapter(chapterName);
- addChapter(chapterName, myChapter);
- }
-
- // Check chapter for missing videos
- for (Map.Entry<String, VideoRecord> videoEntry : theirChapter.getVideos().entrySet()) {
- String videoId = videoEntry.getKey();
- VideoRecord myVideo = myChapter.getVideoRecord(videoId);
-
- if (myVideo == null) {
- myVideo = find(videoId);
- if (myVideo == null) {
- // New Video
- try {
- myVideo = videoEntry.getValue().clone();
- myChapter.setVideoRecord(videoId, myVideo);
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException(e); // Unexpected...
- }
- } else {
- // Video moved
- findChapter(videoId).removeVideoRecord(videoId);
- myChapter.setVideoRecord(videoId, myVideo);
- }
- }
- }
- }
-
- mLastUpdated = source.getLastUpdated();
- }
-}
diff --git a/src/com/p4square/grow/model/Point.java b/src/com/p4square/grow/model/Point.java
deleted file mode 100644
index e9fc0ca..0000000
--- a/src/com/p4square/grow/model/Point.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Simple double based point class.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Point {
- /**
- * Parse a comma separated x,y pair into a point.
- *
- * @return The point represented by the string.
- * @throws IllegalArgumentException if the input is malformed.
- */
- public static Point valueOf(String str) {
- final int comma = str.indexOf(',');
- if (comma == -1 || comma == 0 || comma == str.length() - 1) {
- throw new IllegalArgumentException("Malformed point string");
- }
-
- final String sX = str.substring(0, comma);
- final String sY = str.substring(comma + 1);
-
- return new Point(Double.valueOf(sX), Double.valueOf(sY));
- }
-
- private final double mX;
- private final double mY;
-
- /**
- * Create a new point with the given coordinates.
- *
- * @param x The x coordinate.
- * @param y The y coordinate.
- */
- public Point(double x, double y) {
- mX = x;
- mY = y;
- }
-
- /**
- * Compute the distance between this point and another.
- *
- * @param other The other point.
- * @return The distance between this point and other.
- */
- public double distance(Point other) {
- final double dx = mX - other.mX;
- final double dy = mY - other.mY;
-
- return Math.sqrt(dx*dx + dy*dy);
- }
-
- /**
- * @return The x coordinate.
- */
- public double getX() {
- return mX;
- }
-
- /**
- * @return The y coordinate.
- */
- public double getY() {
- return mY;
- }
-
- /**
- * @return The point represented as a comma separated pair.
- */
- @Override
- public String toString() {
- return String.format("%.2f,%.2f", mX, mY);
- }
-}
diff --git a/src/com/p4square/grow/model/QuadQuestion.java b/src/com/p4square/grow/model/QuadQuestion.java
deleted file mode 100644
index a7b4179..0000000
--- a/src/com/p4square/grow/model/QuadQuestion.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Two-dimensional Question.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class QuadQuestion extends Question {
- private static final ScoringEngine ENGINE = new QuadScoringEngine();
-
- private String mTop;
- private String mRight;
- private String mBottom;
- private String mLeft;
-
- /**
- * @return the top label.
- */
- public String getTop() {
- return mTop;
- }
-
- /**
- * Set the top label.
- * @param s The new top label.
- */
- public void setTop(String s) {
- mTop = s;
- }
-
- /**
- * @return the right label.
- */
- public String getRight() {
- return mRight;
- }
-
- /**
- * Set the right label.
- * @param s The new right label.
- */
- public void setRight(String s) {
- mRight = s;
- }
-
- /**
- * @return the bottom label.
- */
- public String getBottom() {
- return mBottom;
- }
-
- /**
- * Set the bottom label.
- * @param s The new bottom label.
- */
- public void setBottom(String s) {
- mBottom = s;
- }
-
- /**
- * @return the left label.
- */
- public String getLeft() {
- return mLeft;
- }
-
- /**
- * Set the left label.
- * @param s The new left label.
- */
- public void setLeft(String s) {
- mLeft = s;
- }
-
- @Override
- public boolean scoreAnswer(Score score, RecordedAnswer answer) {
- return ENGINE.scoreAnswer(score, this, answer);
- }
-
- @Override
- public QuestionType getType() {
- return QuestionType.QUAD;
- }
-}
diff --git a/src/com/p4square/grow/model/QuadScoringEngine.java b/src/com/p4square/grow/model/QuadScoringEngine.java
deleted file mode 100644
index 33403b5..0000000
--- a/src/com/p4square/grow/model/QuadScoringEngine.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import com.p4square.grow.model.Point;
-
-/**
- * QuadScoringEngine expects the user's answer to be a Point string. We find
- * the closest answer Point to the user's answer and treat that as the answer.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class QuadScoringEngine extends ScoringEngine {
-
- @Override
- public boolean scoreAnswer(Score score, Question question, RecordedAnswer userAnswer) {
- // Find all of the answer points.
- Point[] answers = new Point[question.getAnswers().size()];
- {
- int i = 0;
- for (String answerStr : question.getAnswers().keySet()) {
- answers[i++] = Point.valueOf(answerStr);
- }
- }
-
- // Parse the user's answer.
- Point userPoint = Point.valueOf(userAnswer.getAnswerId());
-
- // Find the closest answer point to the user's answer.
- double minDistance = Double.MAX_VALUE;
- int answerIndex = 0;
- for (int i = 0; i < answers.length; i++) {
- final double distance = userPoint.distance(answers[i]);
- if (distance < minDistance) {
- minDistance = distance;
- answerIndex = i;
- }
- }
-
- LOG.debug("Quad " + question.getId() + ": Got answer "
- + answers[answerIndex].toString() + " for user point " + userAnswer);
-
- // Get the answer and update the score.
- final Answer answer = question.getAnswers().get(answers[answerIndex].toString());
- return answer.score(score);
- }
-}
diff --git a/src/com/p4square/grow/model/Question.java b/src/com/p4square/grow/model/Question.java
deleted file mode 100644
index f4b9458..0000000
--- a/src/com/p4square/grow/model/Question.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonSubTypes;
-import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-/**
- * Model of an assessment question.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-@JsonTypeInfo(
- use = JsonTypeInfo.Id.NAME,
- include = JsonTypeInfo.As.PROPERTY,
- property = "type")
-@JsonSubTypes({
- @Type(value = TextQuestion.class, name = "text"),
- @Type(value = ImageQuestion.class, name = "image"),
- @Type(value = SliderQuestion.class, name = "slider"),
- @Type(value = QuadQuestion.class, name = "quad"),
- @Type(value = CircleQuestion.class, name = "circle"),
-})
-public abstract class Question {
- /**
- * QuestionType indicates the type of Question.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
- public enum QuestionType {
- TEXT,
- IMAGE,
- SLIDER,
- QUAD,
- CIRCLE;
-
- @Override
- public String toString() {
- return name().toLowerCase();
- }
- }
-
- private String mQuestionId;
- private QuestionType mType;
- private String mQuestionText;
- private Map<String, Answer> mAnswers;
-
- private String mPreviousQuestionId;
- private String mNextQuestionId;
-
- public Question() {
- mAnswers = new HashMap<String, Answer>();
- }
-
- /**
- * @return the id String for this question.
- */
- public String getId() {
- return mQuestionId;
- }
-
- /**
- * Set the id String for this question.
- * @param id New id
- */
- public void setId(String id) {
- mQuestionId = id;
- }
-
- /**
- * @return The Question text.
- */
- public String getQuestion() {
- return mQuestionText;
- }
-
- /**
- * Set the question text.
- * @param value The new question text.
- */
- public void setQuestion(String value) {
- mQuestionText = value;
- }
-
- /**
- * @return The id String of the previous question or null if no previous question exists.
- */
- public String getPreviousQuestion() {
- return mPreviousQuestionId;
- }
-
- /**
- * Set the id string of the previous question.
- * @param id Previous question id or null if there is no previous question.
- */
- public void setPreviousQuestion(String id) {
- mPreviousQuestionId = id;
- }
-
- /**
- * @return The id String of the next question or null if no next question exists.
- */
- public String getNextQuestion() {
- return mNextQuestionId;
- }
-
- /**
- * Set the id string of the next question.
- * @param id next question id or null if there is no next question.
- */
- public void setNextQuestion(String id) {
- mNextQuestionId = id;
- }
-
- /**
- * @return a map of Answer id Strings to Answer objects.
- */
- public Map<String, Answer> getAnswers() {
- return mAnswers;
- }
-
- /**
- * Determine the id of the next question based on the answer to this
- * question.
- *
- * @param answerid
- * The id of the selected answer.
- * @return a question id or null if this is the last question.
- */
- public String getNextQuestion(String answerid) {
- String nextQuestion = null;
-
- Answer a = mAnswers.get(answerid);
- if (a != null) {
- nextQuestion = a.getNextQuestion();
- }
-
- if (nextQuestion == null) {
- nextQuestion = mNextQuestionId;
- }
-
- return nextQuestion;
- }
-
- /**
- * Update the score based on the answer to this question.
- *
- * @param score The running score to update.
- * @param answer The answer give to this question.
- * @return true if scoring should continue, false if this answer trumps everything else.
- */
- public abstract boolean scoreAnswer(Score score, RecordedAnswer answer);
-
- /**
- * @return the QuestionType of this question.
- */
- public abstract QuestionType getType();
-
-}
diff --git a/src/com/p4square/grow/model/RecordedAnswer.java b/src/com/p4square/grow/model/RecordedAnswer.java
deleted file mode 100644
index 7d9905d..0000000
--- a/src/com/p4square/grow/model/RecordedAnswer.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Simple model for a user's assessment answer.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class RecordedAnswer {
- private String mAnswerId;
-
- /**
- * @return The user's answer.
- */
- public String getAnswerId() {
- return mAnswerId;
- }
-
- /**
- * Set the answer id field.
- * @param id The new id.
- */
- public void setAnswerId(String id) {
- mAnswerId = id;
- }
-
- @Override
- public String toString() {
- return mAnswerId;
- }
-}
diff --git a/src/com/p4square/grow/model/Score.java b/src/com/p4square/grow/model/Score.java
deleted file mode 100644
index 031c309..0000000
--- a/src/com/p4square/grow/model/Score.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Simple structure containing a score's sum and count.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Score {
- /**
- * Return the decimal value for the given Score String.
- *
- * This method satisfies the invariant for Score x:
- * numericScore(x.toString()) <= x.getScore()
- */
- public static double numericScore(String score) {
- score = score.toLowerCase();
-
- if ("teacher".equals(score)) {
- return 3.5;
- } else if ("disciple".equals(score)) {
- return 2.5;
- } else if ("believer".equals(score)) {
- return 1.5;
- } else if ("seeker".equals(score)) {
- return 0;
- } else {
- return Integer.MAX_VALUE;
- }
- }
-
- double sum;
- int count;
-
- public Score() {
- sum = 0;
- count = 0;
- }
-
- public Score(double sum, int count) {
- this.sum = sum;
- this.count = count;
- }
-
- /**
- * Copy Constructor.
- */
- public Score(Score other) {
- sum = other.sum;
- count = other.count;
- }
-
- /**
- * @return The sum of all the points.
- */
- public double getSum() {
- return sum;
- }
-
- /**
- * @return The number of questions included in the score.
- */
- public int getCount() {
- return count;
- }
-
- /**
- * @return The final score.
- */
- public double getScore() {
- if (count == 0) {
- return 0;
- }
-
- return sum / count;
- }
-
- /**
- * @return the lowest score in the same category as this score.
- */
- public double floor() {
- final double score = getScore();
-
- if (score >= 3.5) {
- return 3.5; // teacher
-
- } else if (score >= 2.5) {
- return 2.5; // disciple
-
- } else if (score >= 1.5) {
- return 1.5; // believer
-
- } else {
- return 0; // seeker
- }
- }
-
- @Override
- public String toString() {
- final double score = getScore();
-
- if (score >= 3.5) {
- return "teacher";
-
- } else if (score >= 2.5) {
- return "disciple";
-
- } else if (score >= 1.5) {
- return "believer";
-
- } else {
- return "seeker";
- }
- }
-
-}
diff --git a/src/com/p4square/grow/model/ScoringEngine.java b/src/com/p4square/grow/model/ScoringEngine.java
deleted file mode 100644
index 8ff18b3..0000000
--- a/src/com/p4square/grow/model/ScoringEngine.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import org.apache.log4j.Logger;
-
-/**
- * ScoringEngine computes the score for a question and a given answer.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public abstract class ScoringEngine {
- protected static final Logger LOG = Logger.getLogger(ScoringEngine.class);
-
- /**
- * Update the score based on the given question and answer.
- *
- * @param score The running score to update.
- * @param question The question to compute the score for.
- * @param answer The answer give to this question.
- * @return true if scoring should continue, false if this answer trumps everything else.
- */
- public abstract boolean scoreAnswer(Score score, Question question, RecordedAnswer answer);
-}
diff --git a/src/com/p4square/grow/model/SimpleScoringEngine.java b/src/com/p4square/grow/model/SimpleScoringEngine.java
deleted file mode 100644
index 6ef2dbb..0000000
--- a/src/com/p4square/grow/model/SimpleScoringEngine.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * SimpleScoringEngine expects the user's answer to a valid answer id and
- * scores accordingly.
- *
- * If the answer id is not valid an Exception is thrown.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SimpleScoringEngine extends ScoringEngine {
-
- @Override
- public boolean scoreAnswer(Score score, Question question, RecordedAnswer userAnswer) {
- final Answer answer = question.getAnswers().get(userAnswer.getAnswerId());
- if (answer == null) {
- throw new IllegalArgumentException("Not a valid answer.");
- }
-
- return answer.score(score);
- }
-}
diff --git a/src/com/p4square/grow/model/SliderQuestion.java b/src/com/p4square/grow/model/SliderQuestion.java
deleted file mode 100644
index f0861e3..0000000
--- a/src/com/p4square/grow/model/SliderQuestion.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Slider Question.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SliderQuestion extends Question {
- private static final ScoringEngine ENGINE = new SliderScoringEngine();
-
- @Override
- public boolean scoreAnswer(Score score, RecordedAnswer answer) {
- return ENGINE.scoreAnswer(score, this, answer);
- }
-
- @Override
- public QuestionType getType() {
- return QuestionType.SLIDER;
- }
-}
diff --git a/src/com/p4square/grow/model/SliderScoringEngine.java b/src/com/p4square/grow/model/SliderScoringEngine.java
deleted file mode 100644
index 2961e95..0000000
--- a/src/com/p4square/grow/model/SliderScoringEngine.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * SliderScoringEngine expects the user's answer to be a decimal value in the
- * range [0, 1]. The value is scaled to the range [1, 4] and added to the
- * score.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SliderScoringEngine extends ScoringEngine {
-
- @Override
- public boolean scoreAnswer(Score score, Question question, RecordedAnswer userAnswer) {
- int numberOfAnswers = question.getAnswers().size();
- if (numberOfAnswers == 0) {
- throw new IllegalArgumentException("Question has no answers.");
- }
-
- double answer = Double.valueOf(userAnswer.getAnswerId());
- if (answer < 0 || answer > 1) {
- throw new IllegalArgumentException("Answer out of bounds.");
- }
-
- double delta = Math.max(1, Math.ceil(answer * numberOfAnswers) / numberOfAnswers * 4);
-
- score.sum += delta;
- score.count++;
-
- return true;
- }
-}
diff --git a/src/com/p4square/grow/model/TextQuestion.java b/src/com/p4square/grow/model/TextQuestion.java
deleted file mode 100644
index 88c2a34..0000000
--- a/src/com/p4square/grow/model/TextQuestion.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Text Question.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class TextQuestion extends Question {
- private static final ScoringEngine ENGINE = new SimpleScoringEngine();
-
- @Override
- public boolean scoreAnswer(Score score, RecordedAnswer answer) {
- return ENGINE.scoreAnswer(score, this, answer);
- }
-
- @Override
- public QuestionType getType() {
- return QuestionType.TEXT;
- }
-}
diff --git a/src/com/p4square/grow/model/TrainingRecord.java b/src/com/p4square/grow/model/TrainingRecord.java
deleted file mode 100644
index bc3ffa9..0000000
--- a/src/com/p4square/grow/model/TrainingRecord.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-/**
- * Representation of a user's training record.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class TrainingRecord {
- private String mLastVideo;
- private Playlist mPlaylist;
-
- public TrainingRecord() {
- mPlaylist = new Playlist();
- }
-
- /**
- * @return Video id of the last video watched.
- */
- public String getLastVideo() {
- return mLastVideo;
- }
-
- /**
- * Set the video id for the last video watched.
- * @param video The new video id.
- */
- public void setLastVideo(String video) {
- mLastVideo = video;
- }
-
- /**
- * @return the user's Playlist.
- */
- public Playlist getPlaylist() {
- return mPlaylist;
- }
-
- /**
- * Set the user's playlist.
- * @param playlist The new playlist.
- */
- public void setPlaylist(Playlist playlist) {
- mPlaylist = playlist;
- }
-}
diff --git a/src/com/p4square/grow/model/UserRecord.java b/src/com/p4square/grow/model/UserRecord.java
deleted file mode 100644
index 4399282..0000000
--- a/src/com/p4square/grow/model/UserRecord.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import org.apache.commons.codec.binary.Hex;
-
-import org.restlet.security.User;
-
-/**
- * A simple user representation without any secrets.
- */
-public class UserRecord {
- private String mId;
- private String mFirstName;
- private String mLastName;
- private String mEmail;
- private String mLanding;
- private boolean mNewBeliever;
-
- // Backend Access
- private String mBackendPasswordHash;
-
- /**
- * Create an empty UserRecord.
- */
- public UserRecord() {
- }
-
- /**
- * Create a new UserRecord with the information from a User.
- */
- public UserRecord(final User user) {
- mId = user.getIdentifier();
- mFirstName = user.getFirstName();
- mLastName = user.getLastName();
- mEmail = user.getEmail();
- }
-
- /**
- * @return The user's identifier.
- */
- public String getId() {
- return mId;
- }
-
- /**
- * Set the user's identifier.
- * @param value The new id.
- */
- public void setId(final String value) {
- mId = value;
- }
-
- /**
- * @return The user's email.
- */
- public String getEmail() {
- return mEmail;
- }
-
- /**
- * Set the user's email.
- * @param value The new email.
- */
- public void setEmail(final String value) {
- mEmail = value;
- }
-
- /**
- * @return The user's first name.
- */
- public String getFirstName() {
- return mFirstName;
- }
-
- /**
- * Set the user's first name.
- * @param value The new first name.
- */
- public void setFirstName(final String value) {
- mFirstName = value;
- }
-
- /**
- * @return The user's last name.
- */
- public String getLastName() {
- return mLastName;
- }
-
- /**
- * Set the user's last name.
- * @param value The new last name.
- */
- public void setLastName(final String value) {
- mLastName = value;
- }
-
- /**
- * @return The user's landing page.
- */
- public String getLanding() {
- return mLanding;
- }
-
- /**
- * Set the user's landing page.
- * @param value The new landing page.
- */
- public void setLanding(final String value) {
- mLanding = value;
- }
-
- /**
- * @return true if the user came from the New Believer's landing.
- */
- public boolean getNewBeliever() {
- return mNewBeliever;
- }
-
- /**
- * Set the user's new believer flag.
- * @param value The new flag.
- */
- public void setNewBeliever(final boolean value) {
- mNewBeliever = value;
- }
-
- /**
- * @return The user's backend password hash, null if he doesn't have
- * access.
- */
- public String getBackendPasswordHash() {
- return mBackendPasswordHash;
- }
-
- /**
- * Set the user's backend password hash.
- * @param value The new backend password hash or null to remove
- * access.
- */
- public void setBackendPasswordHash(final String value) {
- mBackendPasswordHash = value;
- }
-
- /**
- * Set the user's backend password to the clear-text value given.
- * @param value The new backend password.
- */
- public void setBackendPassword(final String value) {
- try {
- mBackendPasswordHash = hashPassword(value);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Hash the given secret.
- */
- public static String hashPassword(final String secret) throws NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance("SHA-1");
-
- // Convert the char[] to byte[]
- // FIXME This approach is incorrectly truncating multibyte
- // characters.
- byte[] b = new byte[secret.length()];
- for (int i = 0; i < secret.length(); i++) {
- b[i] = (byte) secret.charAt(i);
- }
-
- md.update(b);
-
- byte[] hash = md.digest();
- return new String(Hex.encodeHex(hash));
- }
-}
diff --git a/src/com/p4square/grow/model/VideoRecord.java b/src/com/p4square/grow/model/VideoRecord.java
deleted file mode 100644
index ec99d0d..0000000
--- a/src/com/p4square/grow/model/VideoRecord.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.model;
-
-import java.util.Date;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-
-/**
- * Simple bean containing video completion data.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class VideoRecord implements Cloneable {
- private Boolean mComplete;
- private Boolean mRequired;
- private Date mCompletionDate;
-
- public VideoRecord() {
- mComplete = null;
- mRequired = null;
- mCompletionDate = null;
- }
-
- public boolean getComplete() {
- if (mComplete == null) {
- return false;
- }
- return mComplete;
- }
-
- public void setComplete(boolean complete) {
- mComplete = complete;
- }
-
- @JsonIgnore
- public boolean isCompleteSet() {
- return mComplete != null;
- }
-
- public boolean getRequired() {
- if (mRequired == null) {
- return true;
- }
- return mRequired;
- }
-
- public void setRequired(boolean complete) {
- mRequired = complete;
- }
-
- @JsonIgnore
- public boolean isRequiredSet() {
- return mRequired != null;
- }
-
- public Date getCompletionDate() {
- return mCompletionDate;
- }
-
- public void setCompletionDate(Date date) {
- mCompletionDate = date;
- }
-
- /**
- * Convenience method to mark a video complete.
- */
- public void complete() {
- mComplete = true;
- mCompletionDate = new Date();
- }
-
- /**
- * @return an identical clone of this record.
- */
- public VideoRecord clone() throws CloneNotSupportedException {
- VideoRecord r = (VideoRecord) super.clone();
- r.mComplete = mComplete;
- r.mRequired = mRequired;
- r.mCompletionDate = mCompletionDate;
- return r;
- }
-}
diff --git a/src/com/p4square/grow/provider/CollectionProvider.java b/src/com/p4square/grow/provider/CollectionProvider.java
deleted file mode 100644
index e4e9040..0000000
--- a/src/com/p4square/grow/provider/CollectionProvider.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * ListProvider is the logical extension of Provider for dealing with lists of
- * items.
- *
- * @param C The type of the collection key.
- * @param K The type of the item key.
- * @param V The type of the value.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface CollectionProvider<C, K, V> {
- /**
- * Retrieve a specific object from the collection.
- *
- * @param collection The collection key.
- * @param key The key for the object in the collection.
- * @return The object or null if not found.
- */
- V get(C collection, K key) throws IOException;
-
- /**
- * Retrieve a collection.
- *
- * The returned map will never be null.
- *
- * @param collection The collection key.
- * @return A Map of keys to values.
- */
- Map<K, V> query(C collection) throws IOException;
-
- /**
- * Retrieve a portion of a collection.
- *
- * The returned map will never be null.
- *
- * @param collection The collection key.
- * @param limit Max number of items to return.
- * @return A Map of keys to values.
- */
- Map<K, V> query(C collection, int limit) throws IOException;
-
- /**
- * Persist the object with the given key.
- *
- * @param collection The collection key.
- * @param key The key for the object in the collection.
- * @param obj The object to persist.
- */
- void put(C collection, K key, V obj) throws IOException;
-}
diff --git a/src/com/p4square/grow/provider/DelegateCollectionProvider.java b/src/com/p4square/grow/provider/DelegateCollectionProvider.java
deleted file mode 100644
index cf697ba..0000000
--- a/src/com/p4square/grow/provider/DelegateCollectionProvider.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public abstract class DelegateCollectionProvider<C, DC, K, DK, V>
- implements CollectionProvider<C, K, V> {
-
- private CollectionProvider<DC, DK, V> mProvider;
-
- public DelegateCollectionProvider(final CollectionProvider<DC, DK, V> provider) {
- mProvider = provider;
- }
-
- public V get(C collection, K key) throws IOException {
- return mProvider.get(makeCollectionKey(collection), makeKey(key));
- }
-
- public Map<K, V> query(C collection) throws IOException {
- return query(collection, -1);
- }
-
- public Map<K, V> query(C collection, int limit) throws IOException {
- Map<DK, V> delegateResult = mProvider.query(makeCollectionKey(collection), limit);
- Map<K, V> result = new LinkedHashMap<>();
- for (Map.Entry<DK, V> entry : delegateResult.entrySet()) {
- result.put(unmakeKey(entry.getKey()), entry.getValue());
- }
-
- return result;
- }
-
- public void put(C collection, K key, V obj) throws IOException {
- mProvider.put(makeCollectionKey(collection), makeKey(key), obj);
- }
-
- /**
- * Make a collection key for the delegated provider.
- *
- * @param input The pre-transform key.
- * @return the post-transform key.
- */
- protected abstract DC makeCollectionKey(final C input);
-
- /**
- * Make a key for the delegated provider.
- *
- * @param input The pre-transform key.
- * @return the post-transform key.
- */
- protected abstract DK makeKey(final K input);
-
- /**
- * Transform a key for the delegated provider to an input key.
- *
- * @param input The post-transform key.
- * @return the pre-transform key.
- */
- protected abstract K unmakeKey(final DK input);
-}
diff --git a/src/com/p4square/grow/provider/DelegateProvider.java b/src/com/p4square/grow/provider/DelegateProvider.java
deleted file mode 100644
index 42dcc63..0000000
--- a/src/com/p4square/grow/provider/DelegateProvider.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-
-/**
- * DelegateProvider wraps an existing Provider an transforms the key from
- * type K to type D.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public abstract class DelegateProvider<K, D, V> implements Provider<K, V> {
-
- private Provider<D, V> mProvider;
-
- public DelegateProvider(final Provider<D, V> provider) {
- mProvider = provider;
- }
-
- @Override
- public V get(final K key) throws IOException {
- return mProvider.get(makeKey(key));
- }
-
- @Override
- public void put(final K key, final V obj) throws IOException {
- mProvider.put(makeKey(key), obj);
- }
-
- /**
- * Make a Key for the delegated provider.
- *
- * @param input The pre-transform key.
- * @return the post-transform key.
- */
- protected abstract D makeKey(final K input);
-}
diff --git a/src/com/p4square/grow/provider/JsonEncodedProvider.java b/src/com/p4square/grow/provider/JsonEncodedProvider.java
deleted file mode 100644
index 500f761..0000000
--- a/src/com/p4square/grow/provider/JsonEncodedProvider.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-
-/**
- * Provider provides a simple interface for loading and persisting
- * objects.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public abstract class JsonEncodedProvider<V> {
- public static final ObjectMapper MAPPER = new ObjectMapper();
- static {
- MAPPER.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
- MAPPER.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
- MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- }
-
- protected final Class<V> mClazz;
- protected final JavaType mType;
-
- public JsonEncodedProvider(Class<V> clazz) {
- mClazz = clazz;
- mType = null;
- }
-
- public JsonEncodedProvider(JavaType type) {
- mType = type;
- mClazz = null;
- }
-
- /**
- * Encode the object as JSON.
- *
- * @param obj The object to encode.
- * @return The JSON encoding of obj.
- * @throws IOException if the object cannot be encoded.
- */
- protected String encode(V obj) throws IOException {
- if (mClazz == String.class) {
- return (String) obj;
- }
-
- return MAPPER.writeValueAsString(obj);
- }
-
- /**
- * Decode the JSON string as an object.
- *
- * @param blob The JSON data to decode.
- * @return The decoded object or null if blob is null.
- * @throws IOException If an object cannot be decoded.
- */
- protected V decode(String blob) throws IOException {
- if (blob == null) {
- return null;
- }
-
- if (mClazz == String.class) {
- return (V) blob;
- }
-
- V obj;
- if (mClazz != null) {
- obj = MAPPER.readValue(blob, mClazz);
-
- } else {
- obj = MAPPER.readValue(blob, mType);
- }
-
- return obj;
- }
-}
-
diff --git a/src/com/p4square/grow/provider/MapCollectionProvider.java b/src/com/p4square/grow/provider/MapCollectionProvider.java
deleted file mode 100644
index 4c5cef6..0000000
--- a/src/com/p4square/grow/provider/MapCollectionProvider.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2015 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.HashMap;
-
-/**
- * In-memory CollectionProvider implementation, useful for tests.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class MapCollectionProvider<C, K, V> implements CollectionProvider<C, K, V> {
- private final Map<C, Map<K, V>> mMap;
-
- public MapCollectionProvider() {
- mMap = new HashMap<>();
- }
-
- @Override
- public synchronized V get(C collection, K key) throws IOException {
- Map<K, V> map = mMap.get(collection);
- if (map != null) {
- return map.get(key);
- }
-
- return null;
- }
-
- @Override
- public synchronized Map<K, V> query(C collection) throws IOException {
- Map<K, V> map = mMap.get(collection);
- if (map == null) {
- map = new HashMap<K, V>();
- }
-
- return map;
- }
-
- @Override
- public synchronized Map<K, V> query(C collection, int limit) throws IOException {
- Map<K, V> map = query(collection);
-
- if (map.size() > limit) {
- Map<K, V> smallMap = new HashMap<>();
-
- Iterator<Map.Entry<K, V>> iterator = map.entrySet().iterator();
- for (int i = 0; i < limit; i++) {
- Map.Entry<K, V> entry = iterator.next();
- smallMap.put(entry.getKey(), entry.getValue());
- }
-
- return smallMap;
-
- } else {
- return map;
- }
- }
-
- @Override
- public synchronized void put(C collection, K key, V obj) throws IOException {
- Map<K, V> map = mMap.get(collection);
- if (map == null) {
- map = new HashMap<K, V>();
- mMap.put(collection, map);
- }
-
- map.put(key, obj);
- }
-}
diff --git a/src/com/p4square/grow/provider/MapProvider.java b/src/com/p4square/grow/provider/MapProvider.java
deleted file mode 100644
index 40f8107..0000000
--- a/src/com/p4square/grow/provider/MapProvider.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2015 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.HashMap;
-
-/**
- * In-memory Provider implementation, useful for tests.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class MapProvider<K, V> implements Provider<K, V> {
- private final Map<K, V> mMap = new HashMap<K, V>();
-
- @Override
- public V get(K key) throws IOException {
- return mMap.get(key);
- }
-
- @Override
- public void put(K key, V obj) throws IOException {
- mMap.put(key, obj);
- }
-}
diff --git a/src/com/p4square/grow/provider/Provider.java b/src/com/p4square/grow/provider/Provider.java
deleted file mode 100644
index ca6af25..0000000
--- a/src/com/p4square/grow/provider/Provider.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-
-/**
- * Provider provides a simple interface for loading and persisting
- * objects.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface Provider<K, V> {
- /**
- * Retrieve the object with the given key.
- *
- * @param key The key for the object.
- * @return The object or null if not found.
- */
- V get(K key) throws IOException;
-
- /**
- * Persist the object with the given key.
- *
- * @param key The key for the object.
- * @param obj The object to persist.
- */
- void put(K key, V obj) throws IOException;
-}
diff --git a/src/com/p4square/grow/provider/ProvidesAssessments.java b/src/com/p4square/grow/provider/ProvidesAssessments.java
deleted file mode 100644
index 62ba8f6..0000000
--- a/src/com/p4square/grow/provider/ProvidesAssessments.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import com.p4square.grow.model.RecordedAnswer;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface ProvidesAssessments {
- /**
- * Provides a collection of user assessments.
- * The collection key is the user id.
- * The key is the question id.
- */
- CollectionProvider<String, String, String> getAnswerProvider();
-}
diff --git a/src/com/p4square/grow/provider/ProvidesQuestions.java b/src/com/p4square/grow/provider/ProvidesQuestions.java
deleted file mode 100644
index b43f649..0000000
--- a/src/com/p4square/grow/provider/ProvidesQuestions.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import com.p4square.grow.model.Question;
-
-/**
- * Indicates the ability to provide a Question Provider.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface ProvidesQuestions {
- /**
- * @return A Provider of Questions keyed by question id.
- */
- Provider<String, Question> getQuestionProvider();
-}
diff --git a/src/com/p4square/grow/provider/ProvidesStrings.java b/src/com/p4square/grow/provider/ProvidesStrings.java
deleted file mode 100644
index 5d9976e..0000000
--- a/src/com/p4square/grow/provider/ProvidesStrings.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-/**
- * Indicates the ability to provide a String provider.
- *
- * Strings are typically configuration settings stored as a String.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface ProvidesStrings {
- /**
- * @return A Provider of Questions keyed by question id.
- */
- Provider<String, String> getStringProvider();
-} \ No newline at end of file
diff --git a/src/com/p4square/grow/provider/ProvidesTrainingRecords.java b/src/com/p4square/grow/provider/ProvidesTrainingRecords.java
deleted file mode 100644
index 586e649..0000000
--- a/src/com/p4square/grow/provider/ProvidesTrainingRecords.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-
-import com.p4square.grow.model.TrainingRecord;
-import com.p4square.grow.model.Playlist;
-
-/**
- * Indicates the ability to provide a TrainingRecord Provider.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface ProvidesTrainingRecords {
- /**
- * @return A Provider of Questions keyed by question id.
- */
- Provider<String, TrainingRecord> getTrainingRecordProvider();
-
- /**
- * @return the Default Playlist.
- */
- Playlist getDefaultPlaylist() throws IOException;
-}
diff --git a/src/com/p4square/grow/provider/ProvidesUserRecords.java b/src/com/p4square/grow/provider/ProvidesUserRecords.java
deleted file mode 100644
index d77c878..0000000
--- a/src/com/p4square/grow/provider/ProvidesUserRecords.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import com.p4square.grow.model.UserRecord;
-
-/**
- * Indicates the ability to provide a UserRecord Provider.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface ProvidesUserRecords {
- /**
- * @return A Provider of Questions keyed by question id.
- */
- Provider<String, UserRecord> getUserRecordProvider();
-}
diff --git a/src/com/p4square/grow/provider/ProvidesVideos.java b/src/com/p4square/grow/provider/ProvidesVideos.java
deleted file mode 100644
index 3d055d3..0000000
--- a/src/com/p4square/grow/provider/ProvidesVideos.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public interface ProvidesVideos {
- /**
- * @return A Provider of Questions keyed by question id.
- */
- CollectionProvider<String, String, String> getVideoProvider();
-}
diff --git a/src/com/p4square/grow/provider/TrainingRecordProvider.java b/src/com/p4square/grow/provider/TrainingRecordProvider.java
deleted file mode 100644
index 44dba87..0000000
--- a/src/com/p4square/grow/provider/TrainingRecordProvider.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.provider;
-
-import java.io.IOException;
-
-import com.p4square.grow.model.TrainingRecord;
-
-/**
- * TrainingRecordProvider wraps an existing Provider to get and put TrainingRecords.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public abstract class TrainingRecordProvider<K> implements Provider<String, TrainingRecord> {
-
- private Provider<K, TrainingRecord> mProvider;
-
- public TrainingRecordProvider(Provider<K, TrainingRecord> provider) {
- mProvider = provider;
- }
-
- @Override
- public TrainingRecord get(String key) throws IOException {
- return mProvider.get(makeKey(key));
- }
-
- @Override
- public void put(String key, TrainingRecord obj) throws IOException {
- mProvider.put(makeKey(key), obj);
- }
-
- /**
- * Make a Key for a TrainingRecord..
- *
- * @param userId The user id.
- * @return a key for the TrainingRecord of userid.
- */
- protected abstract K makeKey(String userId);
-}
diff --git a/src/com/p4square/grow/tools/AssessmentStats.java b/src/com/p4square/grow/tools/AssessmentStats.java
deleted file mode 100644
index ca83411..0000000
--- a/src/com/p4square/grow/tools/AssessmentStats.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.grow.tools;
-
-
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Queue;
-import java.util.List;
-import java.util.LinkedList;
-import java.io.IOException;
-
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import com.p4square.grow.model.Answer;
-import com.p4square.grow.model.Question;
-import com.p4square.grow.model.RecordedAnswer;
-import com.p4square.grow.model.Score;
-import com.p4square.grow.provider.Provider;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class AssessmentStats {
- public static void main(String... args) throws Exception {
- if (args.length == 0) {
- System.out.println("Usage: AssessmentStats directory firstQuestionId");
- System.exit(1);
- }
-
- Map<String, Question> questions;
- questions = loadQuestions(args[0], args[1]);
-
- // Find the highest possible score
- List<AnswerPath> scores = findHighestFromId(questions, args[1]);
-
- // Print Results
- System.out.printf("Found %d different paths.\n", scores.size());
- int i = 0;
- for (AnswerPath path : scores) {
- Score s = path.mScore;
- System.out.printf("Path %d: %f points, %d questions. Score: %f (%s)\n",
- i++, s.getSum(), s.getCount(), s.getScore(), s.toString());
- System.out.println(" " + path.mPath);
- System.out.println(" " + path.mScores);
- }
- }
-
- private static Map<String, Question> loadQuestions(String baseDir, String firstId) throws IOException {
- FileQuestionProvider provider = new FileQuestionProvider(baseDir);
-
- // Questions to find...
- Queue<String> queue = new LinkedList<>();
- queue.offer(firstId);
-
- Map<String, Question> questions = new HashMap<>();
-
-
- while (!queue.isEmpty()) {
- Question q = provider.get(queue.poll());
- questions.put(q.getId(), q);
-
- if (q.getNextQuestion() != null) {
- queue.offer(q.getNextQuestion());
-
- }
-
- for (Answer a : q.getAnswers().values()) {
- if (a.getNextQuestion() != null) {
- queue.offer(a.getNextQuestion());
- }
- }
-
- // Quick Sanity check
- if (q.getPreviousQuestion() != null) {
- if (questions.get(q.getPreviousQuestion()) == null) {
- throw new IllegalStateException("Haven't seen previous question??");
- }
- }
- }
-
- return questions;
- }
-
- private static List<AnswerPath> findHighestFromId(Map<String, Question> questions, String id) {
- List<AnswerPath> scores = new LinkedList<>();
- doFindHighestFromId(questions, id, scores, new AnswerPath());
- return scores;
- }
-
- private static void doFindHighestFromId(Map<String, Question> questions, String id, List<AnswerPath> scores, AnswerPath path) {
- if (id == null) {
- // End of the road! Save the score and return.
- scores.add(path);
- return;
- }
-
- Question q = questions.get(id);
-
- // Find the best answer following this path and find other paths.
- Score maxScore = path.mScore;
- double max = 0;
-
- int answerCount = 1;
- for (Map.Entry<String, Answer> entry : q.getAnswers().entrySet()) {
- Answer a = entry.getValue();
- RecordedAnswer userAnswer = new RecordedAnswer();
-
- if (q.getType() == Question.QuestionType.SLIDER) {
- // Special Case
- userAnswer.setAnswerId(String.valueOf((float) answerCount / q.getAnswers().size()));
-
- } else {
- userAnswer.setAnswerId(entry.getKey());
- }
-
- Score tempScore = new Score(path.mScore); // Always start with the initial score.
- boolean endOfRoad = !q.scoreAnswer(tempScore, userAnswer);
- double thisScore = tempScore.getSum() - path.mScore.getSum();
-
- if (endOfRoad) {
- // End of Road is a fork too. Record and pick another answer.
- AnswerPath fork = new AnswerPath(path);
- fork.update(id, tempScore);
- scores.add(fork);
-
- } else if (a.getNextQuestion() != null) {
- // Found a new path, follow it.
- // Remember to count this answer in the score.
- AnswerPath fork = new AnswerPath(path);
- fork.update(id, tempScore);
- doFindHighestFromId(questions, a.getNextQuestion(), scores, fork);
-
- } else if (thisScore > max) {
- // Found a higher option that isn't a new path.
- maxScore = tempScore;
- max = thisScore;
- }
-
- answerCount++;
- }
-
- path.update(id, maxScore);
- doFindHighestFromId(questions, q.getNextQuestion(), scores, path);
- }
-
- private static class FileQuestionProvider extends JsonEncodedProvider<Question> implements Provider<String, Question> {
- private String mBaseDir;
-
- public FileQuestionProvider(String directory) {
- super(Question.class);
- mBaseDir = directory;
- }
-
- @Override
- public Question get(String key) throws IOException {
- Path qfile = FileSystems.getDefault().getPath(mBaseDir, key + ".json");
- byte[] blob = Files.readAllBytes(qfile);
- return decode(new String(blob));
- }
-
- @Override
- public void put(String key, Question obj) throws IOException {
- throw new UnsupportedOperationException("Not Implemented");
- }
- }
-
- private static class AnswerPath {
- String mPath;
- String mScores;
- Score mScore;
-
- public AnswerPath() {
- mPath = null;
- mScores = null;
- mScore = new Score();
- }
-
- public AnswerPath(AnswerPath other) {
- mPath = other.mPath;
- mScores = other.mScores;
- mScore = other.mScore;
- }
-
- public void update(String questionId, Score newScore) {
- String value;
-
- if (mScore.getCount() == newScore.getCount()) {
- value = "n/a";
-
- } else {
- double delta = newScore.getSum() - mScore.getSum();
- if (delta < 0) {
- value = "TRUMP";
- } else {
- value = String.valueOf(delta);
- }
- }
-
- if (mPath == null) {
- mPath = questionId;
- mScores = value;
-
- } else {
- mPath += ", " + questionId;
- mScores += " + " + value;
- }
-
- mScore = newScore;
- }
- }
-}
diff --git a/src/com/p4square/grow/tools/AttributeBackfillTool.java b/src/com/p4square/grow/tools/AttributeBackfillTool.java
deleted file mode 100644
index d7fd2ff..0000000
--- a/src/com/p4square/grow/tools/AttributeBackfillTool.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.tools;
-
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-import org.restlet.Client;
-import org.restlet.Context;
-import org.restlet.data.Protocol;
-
-import com.p4square.f1oauth.Attribute;
-import com.p4square.f1oauth.F1API;
-import com.p4square.f1oauth.F1Access;
-import com.p4square.f1oauth.F1Exception;
-import com.p4square.restlet.oauth.OAuthUser;
-
-import com.p4square.grow.backend.dynamo.DynamoDatabase;
-import com.p4square.grow.backend.dynamo.DynamoKey;
-
-import com.p4square.grow.config.Config;
-
-import com.p4square.grow.model.Chapter;
-import com.p4square.grow.model.Playlist;
-import com.p4square.grow.model.TrainingRecord;
-import com.p4square.grow.model.VideoRecord;
-import com.p4square.grow.provider.JsonEncodedProvider;
-
-/**
- * This utility is used to backfill F1 Attributes from the GROW database into F1.
- *
- * This tool currently reads from Dynamo directly. It should probably access the
- * backend or use the {@link com.p4square.grow.backend.GrowData} abstraction instead.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class AttributeBackfillTool {
-
- private static Config mConfig;
- private static F1API mF1API;
- private static DynamoDatabase mDatabase;
-
- public static void usage() {
- System.out.println("java com.p4square.grow.tools.AttributeBackfillTool <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--assessments Backfill All Assessments");
- System.out.println("\t--training Backfill All Training Records");
- }
-
- 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;
- mDatabase = null;
- offset += 2;
-
- } else if ("--dev".equals(args[offset])) {
- mConfig.setDomain("dev");
- mF1API = null;
- mDatabase = null;
- offset += 1;
-
- } else if ("--config".equals(args[offset])) {
- mConfig.updateConfig(args[offset + 1]);
- mF1API = null;
- mDatabase = null;
- offset += 2;
-
- } else if ("--assessments".equals(args[offset])) {
- offset = assessments(args, ++offset);
-
- } else if ("--training".equals(args[offset])) {
- offset = training(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 DynamoDatabase getDatabase() {
- if (mDatabase == null) {
- mDatabase = new DynamoDatabase(mConfig);
- }
-
- return mDatabase;
- }
-
- private static int assessments(String[] args, int offset) throws Exception {
- final F1API f1 = getF1API();
- final DynamoDatabase db = getDatabase();
-
- DynamoKey key = DynamoKey.newKey("assessments", null);
-
- while (key != null) {
- Map<DynamoKey, Map<String, String>> rows = db.getAll(key);
-
- key = null;
-
- for (Map.Entry<DynamoKey, Map<String, String>> row : rows.entrySet()) {
- key = row.getKey();
-
- String userId = key.getHashKey();
-
- String summaryString = row.getValue().get("summary");
- if (summaryString == null || summaryString.length() == 0) {
- System.out.printf("%s assessment incomplete\n", userId);
- continue;
- }
-
- try {
- Map summary = JsonEncodedProvider.MAPPER.readValue(summaryString, Map.class);
-
- String result = (String) summary.get("result");
- if (result == null) {
- System.out.printf("%s assessment incomplete\n", userId);
- continue;
- }
-
- String attributeName = "Assessment Complete - " + result;
-
- // Check if the user already has the attribute.
- List<Attribute> attributes = f1.getAttribute(userId, attributeName);
-
- if (attributes.size() == 0) {
- Attribute attribute = new Attribute(attributeName);
- attribute.setStartDate(new Date());
- attribute.setComment(summaryString);
-
- if (f1.addAttribute(userId, attribute)) {
- System.out.printf("%s attribute added\n", userId);
- } else {
- System.out.printf("%s failed to add attribute\n", userId);
- }
- } else {
- System.out.printf("%s already has attribute\n", userId);
- }
- } catch (Exception e) {
- System.out.printf("%s exception: %s\n", userId, e.getMessage());
- }
- }
- }
-
- return offset;
- }
-
- private static int training(String[] args, int offset) throws Exception {
- final F1API f1 = getF1API();
- final DynamoDatabase db = getDatabase();
-
- DynamoKey key = DynamoKey.newKey("training", null);
-
- while (key != null) {
- Map<DynamoKey, Map<String, String>> rows = db.getAll(key);
-
- key = null;
-
- for (Map.Entry<DynamoKey, Map<String, String>> row : rows.entrySet()) {
- key = row.getKey();
-
- String userId = key.getHashKey();
-
- String valueString = row.getValue().get("value");
- if (valueString == null || valueString.length() == 0) {
- System.out.printf("%s empty training record\n", userId);
- continue;
- }
-
- try {
- TrainingRecord record =
- JsonEncodedProvider.MAPPER.readValue(valueString, TrainingRecord.class);
- Playlist playlist = record.getPlaylist();
-
-chapters:
- for (Map.Entry<String, Chapter> entry : playlist.getChaptersMap().entrySet()) {
- Chapter chapter = entry.getValue();
-
- // Find completion date
- Date complete = new Date(0);
- for (VideoRecord vr : chapter.getVideos().values()) {
- if (!vr.getComplete()) {
- continue chapters;
- }
-
- Date recordCompletion = vr.getCompletionDate();
- if (recordCompletion != null && complete.before(recordCompletion)) {
- complete = vr.getCompletionDate();
- }
- }
-
- String attributeName = "Training Complete - " + entry.getKey();
-
- // Check if the user already has the attribute.
- List<Attribute> attributes = f1.getAttribute(userId, attributeName);
-
- if (attributes.size() == 0) {
- Attribute attribute = new Attribute(attributeName);
- attribute.setStartDate(complete);
-
- if (f1.addAttribute(userId, attribute)) {
- System.out.printf("%s added %s\n", userId, attributeName);
- } else {
- System.out.printf("%s failed to add %s\n", userId, attributeName);
- }
- } else {
- System.out.printf("%s already has %s\n", userId, attributeName);
- }
- }
-
- } catch (Exception e) {
- System.out.printf("%s exception: %s\n", userId, e.getMessage());
- e.printStackTrace();
- }
- }
- }
-
- return offset;
- }
-}
diff --git a/src/com/p4square/grow/tools/AttributeTool.java b/src/com/p4square/grow/tools/AttributeTool.java
deleted file mode 100644
index 8e0540a..0000000
--- a/src/com/p4square/grow/tools/AttributeTool.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.grow.tools;
-
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-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 <userId> <attribute> <comment> Assign an attribute");
- System.out.println("\t--getall <userId> Get an attribute");
- System.out.println("\t--get <userId> <attribute> Get 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 if ("--getall".equals(args[offset])) {
- offset = getall(args, ++offset);
-
- } else if ("--get".equals(args[offset])) {
- offset = get(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(attributeName);
- attribute.setStartDate(new Date());
- attribute.setComment(comment);
-
- if (f1.addAttribute(userId, attribute)) {
- System.out.println("Added attribute " + attributeName + " for " + userId);
- } else {
- System.out.println("Failed to add attribute " + attributeName + " for " + userId);
- }
-
- return offset;
- }
-
- private static int getall(String[] args, int offset) throws Exception {
- final String userId = args[offset++];
-
- doGet(userId, null);
-
- return offset;
- }
-
- private static int get(String[] args, int offset) throws Exception {
- final String userId = args[offset++];
- final String attributeName = args[offset++];
-
- doGet(userId, attributeName);
-
- return offset;
- }
-
- private static void doGet(final String userId, final String attributeName) throws Exception {
- final F1API f1 = getF1API();
-
- List<Attribute> attributes = f1.getAttribute(userId, attributeName);
- for (Attribute attribute : attributes) {
- System.out.printf("%s %s %s %s %s\n%s\n\n",
- userId,
- attribute.getAttributeName(),
- attribute.getId(),
- attribute.getStartDate(),
- attribute.getEndDate(),
- attribute.getComment());
- }
- }
-}
diff --git a/src/com/p4square/restlet/metrics/MetricRouter.java b/src/com/p4square/restlet/metrics/MetricRouter.java
deleted file mode 100644
index d4da270..0000000
--- a/src/com/p4square/restlet/metrics/MetricRouter.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.restlet.metrics;
-
-import com.codahale.metrics.Counter;
-import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.Timer;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.Restlet;
-import org.restlet.routing.TemplateRoute;
-import org.restlet.routing.Router;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class MetricRouter extends Router {
-
- private final MetricRegistry mMetricRegistry;
-
- public MetricRouter(Context context, MetricRegistry metrics) {
- super(context);
- mMetricRegistry = metrics;
- }
-
- @Override
- protected void doHandle(Restlet next, Request request, Response response) {
- String baseName;
- if (next instanceof TemplateRoute) {
- TemplateRoute temp = (TemplateRoute) next;
- baseName = MetricRegistry.name("MetricRouter", temp.getTemplate().getPattern());
- } else {
- baseName = MetricRegistry.name("MetricRouter", "unknown");
- }
-
- final Timer.Context aggTimer = mMetricRegistry.timer("MetricRouter.time").time();
- final Timer.Context timer = mMetricRegistry.timer(baseName + ".time").time();
-
- try {
- super.doHandle(next, request, response);
- } finally {
- timer.stop();
- aggTimer.stop();
-
- // Record status code
- boolean success = !response.getStatus().isError();
- if (success) {
- mMetricRegistry.counter("MetricRouter.success").inc();
- mMetricRegistry.counter(baseName + ".response.success").inc();
- } else {
- mMetricRegistry.counter("MetricRouter.failure").inc();
- mMetricRegistry.counter(baseName + ".response.failure").inc();
- }
- }
- }
-}
diff --git a/src/com/p4square/restlet/metrics/MetricsApplication.java b/src/com/p4square/restlet/metrics/MetricsApplication.java
deleted file mode 100644
index 6caf742..0000000
--- a/src/com/p4square/restlet/metrics/MetricsApplication.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.restlet.metrics;
-
-import java.util.concurrent.TimeUnit;
-
-import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.json.MetricsModule;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import org.restlet.Application;
-import org.restlet.Restlet;
-import org.restlet.resource.Finder;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class MetricsApplication extends Application {
- static final ObjectMapper MAPPER;
- static {
- MAPPER = new ObjectMapper();
- MAPPER.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, true));
- }
-
- private final MetricRegistry mMetricRegistry;
-
- public MetricsApplication(MetricRegistry metrics) {
- mMetricRegistry = metrics;
- }
-
- public MetricRegistry getMetricRegistry() {
- return mMetricRegistry;
- }
-
- @Override
- public Restlet createInboundRoot() {
- return new Finder(getContext(), MetricsResource.class);
- }
-}
diff --git a/src/com/p4square/restlet/metrics/MetricsResource.java b/src/com/p4square/restlet/metrics/MetricsResource.java
deleted file mode 100644
index e2ab14d..0000000
--- a/src/com/p4square/restlet/metrics/MetricsResource.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2014 Jesse Morgan
- */
-
-package com.p4square.restlet.metrics;
-
-import com.codahale.metrics.MetricRegistry;
-
-import org.restlet.ext.jackson.JacksonRepresentation;
-import org.restlet.representation.Representation;
-import org.restlet.resource.ServerResource;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class MetricsResource extends ServerResource {
-
- private MetricRegistry mMetricRegistry;
-
- @Override
- public void doInit() {
- mMetricRegistry = ((MetricsApplication) getApplication()).getMetricRegistry();
- }
-
- @Override
- protected Representation get() {
- JacksonRepresentation<MetricRegistry> rep = new JacksonRepresentation<>(mMetricRegistry);
- rep.setObjectMapper(MetricsApplication.MAPPER);
- return rep;
- }
-}
diff --git a/src/com/p4square/restlet/oauth/OAuthAuthenticator.java b/src/com/p4square/restlet/oauth/OAuthAuthenticator.java
deleted file mode 100644
index c33bb5a..0000000
--- a/src/com/p4square/restlet/oauth/OAuthAuthenticator.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.restlet.oauth;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.security.Authenticator;
-import org.restlet.security.User;
-
-/**
- * Authenticator which makes an OAuth request to authenticate the user.
- *
- * If this Authenticator is made optional than no requests are made to the
- * service provider.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class OAuthAuthenticator extends Authenticator {
- private static Logger LOG = Logger.getLogger(OAuthAuthenticator.class);
-
- private static final String OAUTH_TOKEN = "oauth_token";
- private static final String COOKIE_NAME = "oauth_secret";
-
- private final OAuthHelper mHelper;
-
- /**
- * Create a new Authenticator.
- *
- * @param Context the current context.
- * @param optional If true, unauthenticated users are allowed to continue.
- * @param helper The OAuthHelper which will help with the requests.
- */
- public OAuthAuthenticator(Context context, boolean optional, OAuthHelper helper) {
- super(context, false, optional, null);
-
- mHelper = helper;
- }
-
- protected boolean authenticate(Request request, Response response) {
- /*
- * The authentication workflow has three steps:
- * 1. Get RequestToken
- * 2. Authenticate the user
- * 3. Get AccessToken
- *
- * The authentication workflow is broken into two stages. In the first,
- * we generate the RequestToken (step 1) and redirect the user to the
- * authentication page. When the user comes back, we will request the
- * AccessToken (step 2).
- *
- * We determine which half we are in by the presence of the oauth_token
- * parameter in the query string.
- */
-
- final String token = request.getResourceRef().getQueryAsForm().getFirstValue(OAUTH_TOKEN);
- final String secret = request.getCookies().getFirstValue(COOKIE_NAME);
-
- try {
- if (token == null) {
- if (isOptional()) {
- return false;
- }
-
- // 1. Get RequestToken
- Token requestToken = mHelper.getRequestToken();
-
- if (requestToken == null) {
- return false;
- }
-
- // 2. Redirect user
- // TODO Encrypt cookie
- response.getCookieSettings().add(COOKIE_NAME, requestToken.getSecret());
- response.redirectSeeOther(mHelper.getLoginUrl(requestToken, request.getResourceRef().toString()));
- return false;
-
- } else {
- // 3. Get AccessToken
- Token requestToken = new Token(token, secret);
- User user = mHelper.getAccessToken(requestToken);
- request.getClientInfo().setUser(user);
- return true;
- }
-
- } catch (OAuthException e) {
- LOG.debug("Authentication failed: " + e);
- return false;
- }
- }
-}
diff --git a/src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java b/src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java
deleted file mode 100644
index 76ff044..0000000
--- a/src/com/p4square/restlet/oauth/OAuthAuthenticatorHelper.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.restlet.oauth;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-import java.net.URLEncoder;
-
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import java.util.Collections;
-import java.util.Random;
-
-import javax.crypto.Mac;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.data.ChallengeRequest;
-import org.restlet.data.ChallengeResponse;
-import org.restlet.data.ChallengeScheme;
-import org.restlet.data.CharacterSet;
-import org.restlet.data.Form;
-import org.restlet.data.Method;
-import org.restlet.data.Parameter;
-import org.restlet.data.Reference;
-import org.restlet.engine.header.ChallengeWriter;
-import org.restlet.engine.header.Header;
-import org.restlet.engine.security.AuthenticatorHelper;
-import org.restlet.engine.util.Base64;
-import org.restlet.util.Series;
-
-/**
- * Authentication helper for signing OAuth Requests.
- *
- * This implementation is limited to one consumer token/secret per restlet
- * engine. In practice this means you will only be able to interact with one
- * service provider unless you loaded/unloaded the AuthenticationHelper for
- * each request.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class OAuthAuthenticatorHelper extends AuthenticatorHelper {
- private static final String SIGNATURE_METHOD = "HMAC-SHA1";
- private static final String JAVA_SIGNATURE_METHOD = "HmacSHA1";
- private static final String ENCODING = "UTF-8";
-
- private final Random mRandom;
- private final Token mConsumerToken;
-
- /**
- * Package-private constructor.
- *
- * This class should only be instantiated by OAuthHelper.
- */
- OAuthAuthenticatorHelper(Token consumerToken) {
- super(ChallengeScheme.HTTP_OAUTH, true, false);
-
- mRandom = new Random();
- mConsumerToken = consumerToken;
- }
-
- @Override
- public void formatRequest(ChallengeWriter cw, ChallengeRequest cr,
- Response response, Series<Header> httpHeaders) throws IOException {
-
- throw new UnsupportedOperationException("OAuth Requests are not implemented");
- }
-
- @Override
- public void formatResponse(ChallengeWriter cw, ChallengeResponse response,
- Request request, Series<Header> httpHeaders) {
-
- try {
- Series<Parameter> authParams = new Series<Parameter>(Parameter.class);
-
- String nonce = String.valueOf(mRandom.nextInt());
- String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
-
- authParams.add(new Parameter("oauth_consumer_key", mConsumerToken.getToken()));
- authParams.add(new Parameter("oauth_nonce", nonce));
- authParams.add(new Parameter("oauth_signature_method", SIGNATURE_METHOD));
- authParams.add(new Parameter("oauth_timestamp", timestamp));
- authParams.add(new Parameter("oauth_version", "1.0"));
-
- String accessToken = response.getIdentifier();
- if (accessToken != null) {
- authParams.add(new Parameter("oauth_token", accessToken));
- }
-
- // Generate Signature
- String signature = generateSignature(response, request, authParams);
- authParams.add(new Parameter("oauth_signature", signature));
-
- // Write Header
- for (Parameter p : authParams) {
- cw.appendQuotedChallengeParameter(encode(p.getName()), encode(p.getValue()));
- }
-
- } catch (IOException e) {
- throw new RuntimeException(e);
-
- } catch (InvalidKeyException e) {
- throw new RuntimeException(e);
-
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Helper method to generate an OAuth Signature.
- */
- private String generateSignature(ChallengeResponse response, Request request,
- Series<Parameter> authParams)
- throws NoSuchAlgorithmException, InvalidKeyException, IOException,
- UnsupportedEncodingException {
-
- // HTTP Request Method
- String httpMethod = request.getMethod().getName();
-
- // Request Url
- Reference url = request.getResourceRef();
- String requestUrl = encode(url.getScheme() + ":" + url.getHierarchicalPart());
-
- // Normalized parameters
- Series<Parameter> params = new Series<Parameter>(Parameter.class);
-
- // OAUTH Params
- params.addAll(authParams);
-
- // Query Params
- Form query = url.getQueryAsForm();
- params.addAll(query);
-
- // Sort it
- Collections.sort(params);
-
- StringBuilder normalizedParamsBuilder = new StringBuilder();
- for (Parameter p : params) {
- normalizedParamsBuilder.append('&');
- normalizedParamsBuilder.append(p.encode(CharacterSet.UTF_8));
- }
- String normalizedParams = encode(normalizedParamsBuilder.substring(1)); // remove the first &
-
- // Generate signature base
- String sigBase = httpMethod + "&" + requestUrl + "&" + normalizedParams.toString();
-
- // Sign the signature base
- Mac mac = Mac.getInstance(JAVA_SIGNATURE_METHOD);
-
- String accessTokenSecret = "";
- if (response.getIdentifier() != null) {
- accessTokenSecret = new String(response.getSecret());
- }
-
- byte[] keyBytes = (encode(mConsumerToken.getSecret()) + "&" + encode(accessTokenSecret)).getBytes(ENCODING);
- SecretKey key = new SecretKeySpec(keyBytes, JAVA_SIGNATURE_METHOD);
- mac.init(key);
-
- byte[] signature = mac.doFinal(sigBase.getBytes(ENCODING));
-
- return Base64.encode(signature, false).trim();
- }
-
- /**
- * Helper method to URL Encode Strings.
- */
- private String encode(String input) throws UnsupportedEncodingException {
- return URLEncoder.encode(input, ENCODING);
- }
-}
diff --git a/src/com/p4square/restlet/oauth/OAuthException.java b/src/com/p4square/restlet/oauth/OAuthException.java
deleted file mode 100644
index dd326d3..0000000
--- a/src/com/p4square/restlet/oauth/OAuthException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.restlet.oauth;
-
-import org.restlet.data.Status;
-
-/**
- * Exception throw when the service provider returns an error.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class OAuthException extends Exception {
- private final Status mStatus;
-
- public OAuthException(Status status) {
- super("Service provider failed request: " + status.getDescription());
- mStatus = status;
- }
-
- public Status getStatus() {
- return mStatus;
- }
-}
diff --git a/src/com/p4square/restlet/oauth/OAuthHelper.java b/src/com/p4square/restlet/oauth/OAuthHelper.java
deleted file mode 100644
index 67dd238..0000000
--- a/src/com/p4square/restlet/oauth/OAuthHelper.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.restlet.oauth;
-
-import java.net.URLEncoder;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.Restlet;
-import org.restlet.data.ChallengeResponse;
-import org.restlet.data.ChallengeScheme;
-import org.restlet.data.Form;
-import org.restlet.data.Method;
-import org.restlet.data.Reference;
-import org.restlet.data.Status;
-import org.restlet.engine.Engine;
-import org.restlet.representation.Representation;
-
-/**
- * Helper Class for OAuth 1.0 Authentication.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public abstract class OAuthHelper {
- private final Restlet mDispatcher;
- private final Token mConsumerToken;
-
- /**
- * Create a new OAuth Helper.
- * As currently implemented, there can only be one OAuthHelper per Restlet
- * Engine since this class registers its own provider for the OAuth
- * authentication protocol.
- *
- * FIXME: This could be improved by making OAuthAuthenticationHelper and
- * maybe Token aware of multiple service providers.
- *
- * @param context The restlet context which provides a ClientDispatcher.
- * @param consumerKey The OAuth consumer key for this application.
- * @param consumerSecret the OAuth consumer secret for this application.
- */
- public OAuthHelper(Context context, String consumerKey, String consumerSecret) {
- mDispatcher = context.getClientDispatcher();
- mConsumerToken = new Token(consumerKey, consumerSecret);
-
- Engine.getInstance().getRegisteredAuthenticators().add(new OAuthAuthenticatorHelper(mConsumerToken));
- }
-
- /**
- * @return the URL for the initial RequestToken request.
- */
- protected abstract String getRequestTokenUrl();
-
- /**
- * Request a RequestToken.
- *
- * @return a Token containing the RequestToken.
- * @throws OAuthException if the request fails.
- */
- public Token getRequestToken() throws OAuthException {
- Request request = new Request(Method.GET, getRequestTokenUrl());
- request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_OAUTH));
-
- Response response = mDispatcher.handle(request);
-
- return processTokenRequest(response);
- }
-
- /**
- * @return the URL to redirect the user to for Authentication.
- */
- public abstract String getLoginUrl(Token requestToken, String callback);
-
- /**
- * @return the URL for the AccessToken request.
- */
- protected abstract String getAccessTokenUrl();
-
- /**
- * Request an AccessToken for a previously authenticated RequestToken.
- *
- * @return an OAuthUser object containing the AccessToken.
- * @throws OAuthException if the request fails.
- */
- public OAuthUser getAccessToken(Token requestToken) throws OAuthException {
- Request request = new Request(Method.GET, getAccessTokenUrl());
- request.setChallengeResponse(requestToken.getChallengeResponse());
-
- return processAccessTokenRequest(request);
- }
-
- /**
- * Helper method to decode the token returned from an OAuth Request.
- *
- * @param response The Response object from the Request.
- * @return the Token from the oauth_token and oauth_token_secret parameters.
- * @throws OAuthException is the server reported an error.
- */
- protected Token processTokenRequest(Response response) throws OAuthException {
- Status status = response.getStatus();
- Representation entity = response.getEntity();
-
- try {
- if (status.isSuccess()) {
- Form form = new Form(entity);
- String token = form.getFirstValue("oauth_token");
- String secret = form.getFirstValue("oauth_token_secret");
-
- return new Token(token, secret);
-
- } else {
- throw new OAuthException(status);
- }
- } finally {
- entity.release();
- }
- }
-
- /**
- * Helper method to create an OAuthUser from the AccessToken request.
- *
- * The User's identifier is set to the Content-Location header, if present.
- *
- * @param response The Response to the AccessToken Request.
- * @return An OAuthUser object wrapping the AccessToken.
- * @throws OAuthException if the request failed.
- */
- public OAuthUser processAccessTokenRequest(Request request) throws OAuthException {
- Response response = getResponse(request);
- Token accessToken = processTokenRequest(response);
-
- Reference ref = response.getEntity().getLocationRef();
- if (ref != null) {
- return new OAuthUser(ref.toString(), accessToken);
-
- } else {
- return new OAuthUser(accessToken);
- }
- }
-
- /**
- * Helper method to get a Response for a Request.
- */
- public Response getResponse(Request request) {
- return mDispatcher.handle(request);
- }
-}
diff --git a/src/com/p4square/restlet/oauth/OAuthUser.java b/src/com/p4square/restlet/oauth/OAuthUser.java
deleted file mode 100644
index 11dbac1..0000000
--- a/src/com/p4square/restlet/oauth/OAuthUser.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.restlet.oauth;
-
-import org.restlet.data.ChallengeResponse;
-import org.restlet.security.User;
-
-/**
- * Simple User object which also contains an OAuth AccessToken.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class OAuthUser extends User {
- private final Token mToken;
- private final String mContentLocation;
-
- public OAuthUser(Token token) {
- this(null, token);
- }
-
- public OAuthUser(String location, Token token) {
- super();
- mToken = token;
- mContentLocation = location;
- }
-
- /**
- * @return the Location associated with the user.
- */
- public String getLocation() {
- return mContentLocation;
- }
-
- /**
- * @return The AccessToken.
- */
- public Token getToken() {
- return mToken;
- }
-
- /**
- * Convenience method for getToken().getChallengeResponse().
- * @return A ChallengeResponse based upon the access token.
- */
- public ChallengeResponse getChallengeResponse() {
- return mToken.getChallengeResponse();
- }
-}
diff --git a/src/com/p4square/restlet/oauth/Token.java b/src/com/p4square/restlet/oauth/Token.java
deleted file mode 100644
index 51a9087..0000000
--- a/src/com/p4square/restlet/oauth/Token.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.restlet.oauth;
-
-import org.restlet.data.ChallengeResponse;
-import org.restlet.data.ChallengeScheme;
-
-/**
- * Token wraps the two Strings which make up an OAuth Token: the public
- * component and the private component.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Token {
- private final String mToken;
- private final String mSecret;
-
- public Token(String token, String secret) {
- mToken = token;
- mSecret = secret;
- }
-
- /**
- * @return the public component.
- */
- public String getToken() {
- return mToken;
- }
-
- /**
- * @return the secret component.
- */
- public String getSecret() {
- return mSecret;
- }
-
- @Override
- public String toString() {
- return mToken + "&" + mSecret;
- }
-
- /**
- * Generate a ChallengeResponse based on this Token.
- *
- * @return a ChallengeResponse object using the OAUTH ChallengeScheme.
- */
- public ChallengeResponse getChallengeResponse() {
- return new ChallengeResponse(ChallengeScheme.HTTP_OAUTH, mToken, mSecret);
- }
-}
diff --git a/src/com/p4square/session/Session.java b/src/com/p4square/session/Session.java
deleted file mode 100644
index 1bb65f5..0000000
--- a/src/com/p4square/session/Session.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.session;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import org.restlet.security.User;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Session {
- static final long LIFETIME = 86400000;
-
- private final String mSessionId;
- private final User mUser;
- private final Map<String, String> mData;
- private long mExpires;
-
- Session(User user) {
- mUser = user;
- mSessionId = UUID.randomUUID().toString();
- mExpires = System.currentTimeMillis() + LIFETIME;
- mData = new HashMap<String, String>();
- }
-
- void touch() {
- mExpires = System.currentTimeMillis() + LIFETIME;
- }
-
- boolean isExpired() {
- return System.currentTimeMillis() > mExpires;
- }
-
- public String getId() {
- return mSessionId;
- }
-
- public Object get(String key) {
- return mData.get(key);
- }
-
- public void put(String key, String value) {
- mData.put(key, value);
- }
-
- public User getUser() {
- return mUser;
- }
-
- public Map<String, String> getMap() {
- return mData;
- }
-}
diff --git a/src/com/p4square/session/SessionAuthenticator.java b/src/com/p4square/session/SessionAuthenticator.java
deleted file mode 100644
index 794e1a8..0000000
--- a/src/com/p4square/session/SessionAuthenticator.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.session;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.security.Authenticator;
-import org.restlet.security.User;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SessionAuthenticator /*extends Authenticator*/ {
- /*
- @Override
- protected boolean authenticate(Request request, Response response) {
- // Check for authentication cookie
- final String cookie = request.getCookies().getFirstValue(COOKIE_NAME);
- if (cookie != null) {
- cLog.debug("Got cookie: " + cookie);
- // TODO Decrypt user info
- User user = new User(cookie);
- request.getClientInfo().setUser(user);
- return true;
- }
-
- // Challenge the user if not authenticated
- response.redirectSeeOther(mLoginPage);
- return false;
- }
- */
-}
diff --git a/src/com/p4square/session/SessionCheckingAuthenticator.java b/src/com/p4square/session/SessionCheckingAuthenticator.java
deleted file mode 100644
index 489d6a0..0000000
--- a/src/com/p4square/session/SessionCheckingAuthenticator.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.session;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.security.Authenticator;
-
-/**
- * Authenticator which succeeds if a valid Session exists.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SessionCheckingAuthenticator extends Authenticator {
- private static final Logger LOG = Logger.getLogger(SessionCheckingAuthenticator.class);
-
- public SessionCheckingAuthenticator(Context context, boolean optional) {
- super(context, optional);
- }
-
- protected boolean authenticate(Request request, Response response) {
- Session s = Sessions.getInstance().get(request);
-
- if (s != null) {
- LOG.debug("Found session for user " + s.getUser());
- request.getClientInfo().setUser(s.getUser());
- return true;
-
- } else {
- return false;
- }
- }
-
-}
diff --git a/src/com/p4square/session/SessionCookieAuthenticator.java b/src/com/p4square/session/SessionCookieAuthenticator.java
deleted file mode 100644
index 0074b77..0000000
--- a/src/com/p4square/session/SessionCookieAuthenticator.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.session;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.security.Authenticator;
-
-/**
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SessionCookieAuthenticator extends Authenticator {
- private static final Logger LOG = Logger.getLogger(SessionCookieAuthenticator.class);
-
- private static final String COOKIE_NAME = "S";
-
- private final Sessions mSessions;
-
- public SessionCookieAuthenticator(Context context, boolean optional, Sessions sessions) {
- super(context, optional);
-
- mSessions = sessions;
- }
-
- protected boolean authenticate(Request request, Response response) {
- final String cookie = request.getCookies().getFirstValue(COOKIE_NAME);
-
- if (request.getClientInfo().isAuthenticated()) {
- // Request is already authenticated... create session if it doesn't exist.
- if (cookie == null) {
- Session s = mSessions.create(request.getClientInfo().getUser());
- response.getCookieSettings().add(COOKIE_NAME, s.getId());
- }
-
- return true;
-
- } else {
- // Check for authentication cookie
- if (cookie != null) {
- LOG.debug("Got cookie: " + cookie);
-
- Session s = mSessions.get(cookie);
- if (s != null) {
- request.getClientInfo().setUser(s.getUser());
- return true;
- }
- }
-
- return false;
- }
- }
-
-}
diff --git a/src/com/p4square/session/SessionCreatingAuthenticator.java b/src/com/p4square/session/SessionCreatingAuthenticator.java
deleted file mode 100644
index 3ec14b4..0000000
--- a/src/com/p4square/session/SessionCreatingAuthenticator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.session;
-
-import org.apache.log4j.Logger;
-
-import org.restlet.Context;
-import org.restlet.Request;
-import org.restlet.Response;
-import org.restlet.security.Authenticator;
-import org.restlet.security.User;
-
-/**
- * Authenticator which creates a Session for the request and adds a cookie
- * to the response.
- *
- * The Request MUST be Authenticated and MUST have a User object associated.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class SessionCreatingAuthenticator extends Authenticator {
- private static final Logger LOG = Logger.getLogger(SessionCreatingAuthenticator.class);
-
- public SessionCreatingAuthenticator(Context context) {
- super(context, true);
- }
-
- protected boolean authenticate(Request request, Response response) {
- if (Sessions.getInstance().get(request) != null) {
- return true;
- }
-
- User user = request.getClientInfo().getUser();
-
- if (request.getClientInfo().isAuthenticated() && user != null) {
- Sessions.getInstance().create(request, response);
- LOG.debug(response);
- return true;
- }
-
- return false;
- }
-
-}
diff --git a/src/com/p4square/session/Sessions.java b/src/com/p4square/session/Sessions.java
deleted file mode 100644
index 9f9dda0..0000000
--- a/src/com/p4square/session/Sessions.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2013 Jesse Morgan
- */
-
-package com.p4square.session;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.restlet.Response;
-import org.restlet.Request;
-import org.restlet.data.CookieSetting;
-import org.restlet.security.User;
-
-/**
- * Singleton Session Manager.
- *
- * @author Jesse Morgan <jesse@jesterpm.net>
- */
-public class Sessions {
- private static final String COOKIE_NAME = "S";
- private static final int DELETE = 0;
-
- private static final Sessions THE = new Sessions();
- public static Sessions getInstance() {
- return THE;
- }
-
- private final Map<String, Session> mSessions;
- private final Timer mCleanupTimer;
-
- private Sessions() {
- mSessions = new ConcurrentHashMap<String, Session>();
-
- mCleanupTimer = new Timer("sessionCleaner", true);
- mCleanupTimer.scheduleAtFixedRate(new TimerTask() {
- @Override
- public void run() {
- for (Session s : mSessions.values()) {
- if (s.isExpired()) {
- mSessions.remove(s.getId());
- }
- }
- }
- }, Session.LIFETIME, Session.LIFETIME);
- }
-
- /**
- * Get a session by ID.
- *
- * @param sessionid
- * The Session id
- * @return The Session if found and not expired, null otherwise.
- */
- public Session get(String sessionid) {
- Session s = mSessions.get(sessionid);
-
- if (s != null && !s.isExpired()) {
- s.touch();
- return s;
- }
-
- return null;
- }
-
- /**
- * Get the Session associated with the Request.
- *
- * @param request
- * The request to fetch a session for.
- * @return A session or null if no session is found.
- */
- public Session get(Request request) {
- final String cookie = request.getCookies().getFirstValue(COOKIE_NAME);
-
- if (cookie != null) {
- return get(cookie);
- }
-
- return null;
- }
-
- /**
- * Create a new Session for the given User object.
- *
- * @param user
- * The User to associate with the Session.
- * @return The new Session object.
- */
- public Session create(User user) {
- if (user == null) {
- throw new IllegalArgumentException("Can not create session for null user.");
- }
-
- Session s = new Session(user);
- mSessions.put(s.getId(), s);
-
- return s;
- }
-
- /**
- * Delete a Session.
- *
- * @param sessionid
- * The id of the Session to remove.
- */
- public void delete(String sessionid) {
- mSessions.remove(sessionid);
- }
-
- /**
- * Create a new Session and add the Session cookie to the response.
- *
- * @param request
- * The request to create the Session for.
- * @param response
- * The response to add the session cookie to.
- * @return The new Session.
- */
- public Session create(Request request, Response response) {
- Session s = create(request.getClientInfo().getUser());
-
- CookieSetting cookie = new CookieSetting(COOKIE_NAME, s.getId());
- cookie.setPath("/");
-
- request.getCookies().add(cookie);
- response.getCookieSettings().add(cookie);
-
- return s;
- }
-
- /**
- * Remove a Session and delete the cookies.
- *
- * @param request
- * The request with the session cookie to remove
- * @param response
- * The response to remove the session cookie from.
- */
- public void delete(Request request, Response response) {
- final String sessionid = request.getCookies().getFirstValue(COOKIE_NAME);
-
- delete(sessionid);
-
- CookieSetting cookie = new CookieSetting(COOKIE_NAME, "");
- cookie.setPath("/");
- cookie.setMaxAge(DELETE);
-
- request.getCookies().add(cookie);
- response.getCookieSettings().add(cookie);
- }
-
-}