summaryrefslogtreecommitdiff
path: root/src/main/java/com/p4square/grow
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/p4square/grow')
-rw-r--r--src/main/java/com/p4square/grow/ccb/CCBProgressReporter.java2
-rw-r--r--src/main/java/com/p4square/grow/frontend/GrowFrontend.java9
-rw-r--r--src/main/java/com/p4square/grow/frontend/TrainingPageResource.java61
-rw-r--r--src/main/java/com/p4square/grow/model/Chapter.java21
4 files changed, 73 insertions, 20 deletions
diff --git a/src/main/java/com/p4square/grow/ccb/CCBProgressReporter.java b/src/main/java/com/p4square/grow/ccb/CCBProgressReporter.java
index 6eb9c15..c352fc7 100644
--- a/src/main/java/com/p4square/grow/ccb/CCBProgressReporter.java
+++ b/src/main/java/com/p4square/grow/ccb/CCBProgressReporter.java
@@ -57,7 +57,7 @@ public class CCBProgressReporter implements ProgressReporter {
if (currentLevel != null) {
if (Score.numericScore(chapter) <= Score.numericScore(currentLevel.getSelection().getLabel())) {
- LOG.info("Not updating level for " + user.getIdentifier()
+ LOG.debug("Not updating level for " + user.getIdentifier()
+ " because current level (" + currentLevel.getSelection().getLabel()
+ ") is greater than new level (" + chapter + ")");
return;
diff --git a/src/main/java/com/p4square/grow/frontend/GrowFrontend.java b/src/main/java/com/p4square/grow/frontend/GrowFrontend.java
index b5f62fb..ebaa8df 100644
--- a/src/main/java/com/p4square/grow/frontend/GrowFrontend.java
+++ b/src/main/java/com/p4square/grow/frontend/GrowFrontend.java
@@ -7,6 +7,8 @@ package com.p4square.grow.frontend;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import freemarker.template.Template;
@@ -51,6 +53,8 @@ public class GrowFrontend extends FMFacade {
private IntegrationDriver mIntegrationFactory;
+ private final ExecutorService mThreadPool;
+
public GrowFrontend() {
this(new Config(), new MetricRegistry());
}
@@ -58,6 +62,7 @@ public class GrowFrontend extends FMFacade {
public GrowFrontend(Config config, MetricRegistry metricRegistry) {
mConfig = config;
mMetricRegistry = metricRegistry;
+ mThreadPool = Executors.newFixedThreadPool(mConfig.getInt("threadPoolSize", 10));
}
public Config getConfig() {
@@ -68,6 +73,10 @@ public class GrowFrontend extends FMFacade {
return mMetricRegistry;
}
+ public ExecutorService getThreadPool() {
+ return mThreadPool;
+ }
+
@Override
public synchronized void start() throws Exception {
Template errorTemplate = getTemplate("templates/error.ftl");
diff --git a/src/main/java/com/p4square/grow/frontend/TrainingPageResource.java b/src/main/java/com/p4square/grow/frontend/TrainingPageResource.java
index a1e7789..108c7a7 100644
--- a/src/main/java/com/p4square/grow/frontend/TrainingPageResource.java
+++ b/src/main/java/com/p4square/grow/frontend/TrainingPageResource.java
@@ -4,24 +4,22 @@
package com.p4square.grow.frontend;
-import java.util.ArrayList;
+import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
+import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ExecutorService;
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;
@@ -36,6 +34,7 @@ import com.p4square.grow.model.VideoRecord;
import com.p4square.grow.model.Playlist;
import com.p4square.grow.provider.TrainingRecordProvider;
import com.p4square.grow.provider.Provider;
+import org.restlet.security.User;
/**
* TrainingPageResource handles rendering the training page.
@@ -49,26 +48,25 @@ 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);
+ private static final Comparator<Map<String, Object>> VIDEO_COMPARATOR = (left, right) -> {
+ String leftNumberStr = (String) left.get("number");
+ String rightNumberStr = (String) right.get("number");
- return Double.compare(leftNumber, rightNumber);
+ 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 ExecutorService mThreadPool;
+ private ProgressReporter mProgressReporter;
private Provider<String, TrainingRecord> mTrainingRecordProvider;
private FeedData mFeedData;
@@ -90,12 +88,14 @@ public class TrainingPageResource extends FreeMarkerPageResource {
}
mJsonClient = new JsonRequestClient(getContext().getClientDispatcher());
- mTrainingRecordProvider = new TrainingRecordProvider<String>(new JsonRequestProvider<TrainingRecord>(getContext().getClientDispatcher(), TrainingRecord.class)) {
+ mTrainingRecordProvider = new TrainingRecordProvider<String>(new JsonRequestProvider<>(getContext().getClientDispatcher(), TrainingRecord.class)) {
@Override
public String makeKey(String userid) {
return getBackendEndpoint() + "/accounts/" + userid + "/training";
}
};
+ mThreadPool = growFrontend.getThreadPool();
+ mProgressReporter = growFrontend.getThirdPartyIntegrationFactory().getProgressReporter();
mFeedData = new FeedData(getContext(), mConfig);
@@ -125,6 +125,7 @@ public class TrainingPageResource extends FreeMarkerPageResource {
// to skip ahead.
boolean allowUserToSkip = mConfig.getBoolean("allowUserToSkip", false) || getQueryValue("magicskip") != null;
String defaultChapter = null;
+ String highestCompletedChapter = null;
boolean userTriedToSkip = false;
int overallProgress = 0;
@@ -152,6 +153,7 @@ public class TrainingPageResource extends FreeMarkerPageResource {
allowedChapters.put(chapterId, allowed);
if (completed) {
+ highestCompletedChapter = chapterId;
overallProgress++;
}
}
@@ -227,6 +229,27 @@ public class TrainingPageResource extends FreeMarkerPageResource {
root.put("feeddata", mFeedData);
}
+ // Updated the integration database with the last completed chapter,
+ // just in case this failed previously.
+ if (highestCompletedChapter != null) {
+ try {
+ final User user = getRequest().getClientInfo().getUser();
+ // Get the date of the highest completed chapter.
+ final Date completionDate = playlist.getChaptersMap().get(highestCompletedChapter).getCompletionDate();
+ final String completedChapter = highestCompletedChapter;
+ mThreadPool.execute(() -> {
+ try {
+ mProgressReporter.reportChapterComplete(user, completedChapter, completionDate);
+ } catch (IOException e) {
+ LOG.error("Failed to sync progress", e);
+ }
+ });
+ } catch (Throwable e) {
+ // Don't let any failures here fail the page load.
+ LOG.error("Unexpected throwable", e);
+ }
+ }
+
return new TemplateRepresentation(mTrainingTemplate, root, MediaType.TEXT_HTML);
} catch (Exception e) {
diff --git a/src/main/java/com/p4square/grow/model/Chapter.java b/src/main/java/com/p4square/grow/model/Chapter.java
index 3a08e4c..ac27de6 100644
--- a/src/main/java/com/p4square/grow/model/Chapter.java
+++ b/src/main/java/com/p4square/grow/model/Chapter.java
@@ -4,6 +4,7 @@
package com.p4square.grow.model;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -98,6 +99,26 @@ public class Chapter implements Cloneable {
}
/**
+ * @return the completion date for the chapter, or null if it has not been completed.
+ */
+ @JsonIgnore
+ public Date getCompletionDate() {
+ Date latest = new Date(0);
+ for (VideoRecord video : mVideos.values()) {
+ if (video.getRequired() && !video.getComplete()) {
+ // Hey, this chapter isn't complete!
+ return null;
+ }
+
+ Date completionDate = video.getCompletionDate();
+ if (completionDate.after(latest)) {
+ latest = completionDate;
+ }
+ }
+ return latest;
+ }
+
+ /**
* Deeply clone a chapter.
*
* @return a new Chapter object identical but independent of this one.