diff options
Diffstat (limited to 'src/com/p4square/grow')
6 files changed, 344 insertions, 30 deletions
| diff --git a/src/com/p4square/grow/backend/resources/Playlist.java b/src/com/p4square/grow/backend/resources/Playlist.java new file mode 100644 index 0000000..f3d2f08 --- /dev/null +++ b/src/com/p4square/grow/backend/resources/Playlist.java @@ -0,0 +1,134 @@ +/* + * Copyright 2013 Jesse Morgan + */ + +package com.p4square.grow.backend.resources; + +import java.io.IOException; + +import java.util.HashMap; +import java.util.Map; + +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; + +import com.p4square.grow.backend.db.CassandraDatabase; + +/** + *  + * @author Jesse Morgan <jesse@jesterpm.net> + */ +class Playlist { +    private static final ObjectMapper MAPPER = new ObjectMapper(); + +    /** +     * Load a Playlist from the database. +     */ +    public static Playlist load(CassandraDatabase db, String userId) throws IOException { +        String playlistString = db.getKey("training", userId, "playlist"); + +        if (playlistString == null) { +            return null; +        } + +        Map<String, Map<String, VideoRecord>> playlist = +            MAPPER.readValue(playlistString, new TypeReference<Map<String, Map<String, VideoRecord>>>() { }); + +        return new Playlist(playlist); + +    } + +    /** +     * Persist the Playlist for the given user. +     * @return The String serialization of the playlist. +     */ +    public static String save(CassandraDatabase db, String userId, Playlist playlist) throws IOException { +        String playlistString = MAPPER.writeValueAsString(playlist.mPlaylist); +        db.putKey("training", userId, "playlist", playlistString); +        return playlistString; +    } + + +    private Map<String, Map<String, VideoRecord>> mPlaylist; + +    /** +     * Construct an empty playlist. +     */ +    public Playlist() { +        mPlaylist = new HashMap<String, Map<String, VideoRecord>>(); +    } + +    /** +     * Constructor for database initialization. +     */ +    private Playlist(Map<String, Map<String, VideoRecord>> playlist) { +        mPlaylist = playlist; +    } + +    public VideoRecord find(String videoId) { +        for (Map<String, VideoRecord> chapter : mPlaylist.values()) { +            VideoRecord r = chapter.get(videoId); + +            if (r != null) { +                return r; +            } +        } + +        return null; +    } + +    /** +     * Add a video to the playlist. +     */ +    public VideoRecord add(String chapter, String videoId) { +        Map<String, VideoRecord> chapterMap = mPlaylist.get(chapter); + +        if (chapterMap == null) { +            chapterMap = new HashMap<String, VideoRecord>(); +            mPlaylist.put(chapter, chapterMap); +        } + +        VideoRecord r = new VideoRecord(); +        chapterMap.put(videoId, r); +        return r; +    } + +    /** +     * @return The last chapter to be completed. +     */ +    public Map<String, Boolean> getChapterStatuses() { +        Map<String, Boolean> completed = new HashMap<String, Boolean>(); + +        for (String chapter : mPlaylist.keySet()) { +            completed.put(chapter, isChapterComplete(chapter)); +        } + +        return completed; +    } + +    public boolean isChapterComplete(String chapterId) { +        boolean complete = true; + +        Map<String, VideoRecord> chapter = mPlaylist.get(chapterId); +        if (chapter != null) { +            for (VideoRecord r : chapter.values()) { +                if (r.getRequired() && !r.getComplete()) { +                    return false; +                } +            } +        } + +        return complete; +    } + +    @Override +    public String toString() { +        try { +            return MAPPER.writeValueAsString(mPlaylist); + +        } catch (IOException e) { +            return super.toString(); +        } +    } + +} diff --git a/src/com/p4square/grow/backend/resources/Score.java b/src/com/p4square/grow/backend/resources/Score.java index c7e5ecc..6f52c02 100644 --- a/src/com/p4square/grow/backend/resources/Score.java +++ b/src/com/p4square/grow/backend/resources/Score.java @@ -10,6 +10,21 @@ package com.p4square.grow.backend.resources;   * @author Jesse Morgan <jesse@jesterpm.net>   */  class Score { +    /** +     * Return the integer value for the given Score String. +     */ +    public static int numericScore(String score) { +        if ("teacher".equals(score)) { +            return 4; +        } else if ("disciple".equals(score)) { +            return 3; +        } else if ("believer".equals(score)) { +            return 2; +        } else { +            return 1; +        } +    } +      double sum;      int count; diff --git a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java index 5e4a8bb..e93e253 100644 --- a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java +++ b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java @@ -31,7 +31,7 @@ import com.p4square.grow.backend.db.CassandraDatabase;  public class SurveyResultsResource extends ServerResource {      private final static Logger cLog = Logger.getLogger(SurveyResultsResource.class); -    private final static ObjectMapper cMapper = new ObjectMapper(); +    private final static ObjectMapper MAPPER = new ObjectMapper();      static enum RequestType {          ASSESSMENT, ANSWER @@ -72,7 +72,10 @@ public class SurveyResultsResource extends ServerResource {                  break;              case ASSESSMENT: -                result = buildAssessment(); +                result = mDb.getKey("assessments", mUserId, "summary"); +                if (result == null) { +                    result = buildAssessment(); +                }                  break;          } @@ -135,7 +138,7 @@ public class SurveyResultsResource extends ServerResource {          if (!row.isEmpty()) {              Score score = new Score();              for (Column<String> c : row) { -                if (c.getName().equals("lastAnswered")) { +                if (c.getName().equals("lastAnswered") || c.getName().equals("summary")) {                      continue;                  } @@ -153,7 +156,12 @@ public class SurveyResultsResource extends ServerResource {          }          sb.append(" }"); -        return sb.toString(); +        String summary = sb.toString(); + +        // Persist summary +        mDb.putKey("assessments", mUserId, "summary", summary); + +        return summary;      }      private boolean scoreQuestion(final Score score, final String questionId, @@ -162,8 +170,8 @@ public class SurveyResultsResource extends ServerResource {          final String data = mDb.getKey("strings", "/questions/" + questionId);          try { -            final Map<?,?> questionMap = cMapper.readValue(data, Map.class); -            final Map<?,?> answerMap = cMapper.readValue(answerJson, Map.class); +            final Map<?,?> questionMap = MAPPER.readValue(data, Map.class); +            final Map<?,?> answerMap = MAPPER.readValue(answerJson, Map.class);              final Question question = new Question((Map<String, Object>) questionMap);              final String answerId = (String) answerMap.get("answerId"); diff --git a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java b/src/com/p4square/grow/backend/resources/TrainingRecordResource.java index 93f4fbc..8447c16 100644 --- a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java +++ b/src/com/p4square/grow/backend/resources/TrainingRecordResource.java @@ -4,12 +4,18 @@  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.netflix.astyanax.model.Column;  import com.netflix.astyanax.model.ColumnList; +import org.codehaus.jackson.map.ObjectMapper; +  import org.restlet.data.MediaType;  import org.restlet.data.Status;  import org.restlet.resource.ServerResource; @@ -22,16 +28,19 @@ import com.p4square.grow.backend.GrowBackend;  import com.p4square.grow.backend.db.CassandraDatabase;  /** - *  + *   * @author Jesse Morgan <jesse@jesterpm.net>   */  public class TrainingRecordResource extends ServerResource { -    private final static Logger cLog = Logger.getLogger(TrainingRecordResource.class); +    private static final String[] CHAPTERS = { "seeker", "believer", "disciple", "teacher" }; + +    private static final Logger LOG = Logger.getLogger(TrainingRecordResource.class); +    private static final ObjectMapper MAPPER = new ObjectMapper();      static enum RequestType {          SUMMARY, VIDEO      } -     +      private GrowBackend mBackend;      private CassandraDatabase mDb; @@ -76,7 +85,7 @@ public class TrainingRecordResource extends ServerResource {              setStatus(Status.CLIENT_ERROR_NOT_FOUND);              return null;          } -         +          return new StringRepresentation(result);      } @@ -92,10 +101,20 @@ public class TrainingRecordResource extends ServerResource {                  try {                      mDb.putKey("training", mUserId, mVideoId, entity.getText());                      mDb.putKey("training", mUserId, "lastVideo", mVideoId); + +                    Playlist playlist = Playlist.load(mDb, mUserId); +                    if (playlist != null) { +                        VideoRecord r = playlist.find(mVideoId); +                        if (r != null && !r.getComplete()) { +                            r.complete(); +                            Playlist.save(mDb, mUserId, playlist); +                        } +                    } +                      success = true;                  } catch (Exception e) { -                    cLog.warn("Caught exception updating training record: " + e.getMessage(), e); +                    LOG.warn("Caught exception updating training record: " + e.getMessage(), e);                  }                  break; @@ -119,19 +138,20 @@ public class TrainingRecordResource extends ServerResource {      private String buildSummary() {          StringBuilder sb = new StringBuilder("{ "); -        // Last question answered +        // Last watch video          final String lastVideo = mDb.getKey("training", mUserId, "lastVideo");          if (lastVideo != null) {              sb.append("\"lastVideo\": \"" + lastVideo + "\", ");          } -        // List of videos watched +        // Get the user's video history          sb.append("\"videos\": { ");          ColumnList<String> row = mDb.getRow("training", mUserId);          if (!row.isEmpty()) {              boolean first = true;              for (Column<String> c : row) { -                if ("lastVideo".equals(c.getName())) { +                if ("lastVideo".equals(c.getName()) || +                    "playlist".equals(c.getName())) {                      continue;                  } @@ -142,14 +162,69 @@ public class TrainingRecordResource extends ServerResource {                      sb.append(", \"" + c.getName() + "\": ");                  } -                sb.append(c.getStringValue());  +                sb.append(c.getStringValue());              }          }          sb.append(" }"); +        // Get the user's playlist +        try { +            Playlist playlist = Playlist.load(mDb, mUserId); +            if (playlist == null) { +                playlist = createInitialPlaylist(); +            } + +            sb.append(", \"playlist\": "); +            sb.append(playlist.toString()); + +            // Last Completed Section +            Map<String, Boolean> chapters = playlist.getChapterStatuses(); +            String chaptersString = MAPPER.writeValueAsString(chapters); +            sb.append(", \"chapters\":"); +            sb.append(chaptersString); + + +        } catch (IOException e) { +            LOG.warn("IOException loading playlist for user " + mUserId, e); +        } +          sb.append(" }");          return sb.toString();      } -      + +    /** +     * Create the user's initial playlist. +     * +     * @return Returns the String representation of the initial playlist. +     */ +    private Playlist createInitialPlaylist() throws IOException { +        Playlist playlist = new Playlist(); + +        // Get assessment score +        String summaryString = mDb.getKey("assessments", mUserId, "summary"); +        if (summaryString == null) { +            return null; +        } +        Map<?,?> summary = MAPPER.readValue(summaryString, Map.class); +        double score = (Double) summary.get("score"); + +        // Get videos for each section and build playlist +        for (String chapter : CHAPTERS) { +            // Chapter required if the floor of the score is <= the chapter's numeric value. +            boolean required = score < Score.numericScore(chapter) + 1; + +            ColumnList<String> row = mDb.getRow("strings", "/training/" + chapter); +            if (!row.isEmpty()) { +                for (Column<String> c : row) { +                    VideoRecord r = playlist.add(chapter, c.getName()); +                    r.setRequired(required); +                } +            } +        } + +        Playlist.save(mDb, mUserId, playlist); + +        return playlist; +    }  } diff --git a/src/com/p4square/grow/backend/resources/VideoRecord.java b/src/com/p4square/grow/backend/resources/VideoRecord.java new file mode 100644 index 0000000..2ba28c3 --- /dev/null +++ b/src/com/p4square/grow/backend/resources/VideoRecord.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Jesse Morgan + */ + +package com.p4square.grow.backend.resources; + +import java.util.Date; + +/** + * Simple bean containing video completion data. + * + * @author Jesse Morgan <jesse@jesterpm.net> + */ +class VideoRecord { +    private boolean mComplete; +    private boolean mRequired; +    private Date mCompletionDate; + +    public VideoRecord() { +        mComplete = false; +        mRequired = true; +        mCompletionDate = null; +    } + +    public boolean getComplete() { +        return mComplete; +    } + +    public void setComplete(boolean complete) { +        mComplete = complete; +    } + +    public boolean getRequired() { +        return mRequired; +    } + +    public void setRequired(boolean complete) { +        mRequired = complete; +    } + +    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(); +    } +} diff --git a/src/com/p4square/grow/frontend/TrainingPageResource.java b/src/com/p4square/grow/frontend/TrainingPageResource.java index 6615295..c6c86c3 100644 --- a/src/com/p4square/grow/frontend/TrainingPageResource.java +++ b/src/com/p4square/grow/frontend/TrainingPageResource.java @@ -16,6 +16,7 @@ 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; @@ -70,10 +71,34 @@ public class TrainingPageResource extends FreeMarkerPageResource {      @Override      protected Representation get() {          try { -            // Get the current chapter. +            // Get the training summary +            Map<String, Object> trainingRecord = null; +            Map<String, Object> completedVideos = new HashMap<String, Object>(); +            Map<String, Boolean> chapters = null; +            { +                JsonResponse response = backendGet("/accounts/" + mUserId + "/training"); +                if (response.getStatus().isSuccess()) { +                    trainingRecord = response.getMap(); +                    completedVideos = (Map<String, Object>) trainingRecord.get("videos"); +                    chapters = (Map<String, Boolean>) trainingRecord.get("chapters"); +                } +            } + +            // Get the current chapter (the lowest, incomplete chapter)              if (mChapter == null) { -                // TODO: Get user's current question -                mChapter = "seeker"; +                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; +                        mChapter = chapter.getKey(); +                    } +                } + +                String nextPage = mConfig.getString("dynamicRoot", ""); +                nextPage += "/account/training/" + mChapter; +                getResponse().redirectSeeOther(nextPage); +                return new StringRepresentation("Redirecting to " + nextPage);              }              // Get videos for the chapter. @@ -87,17 +112,6 @@ public class TrainingPageResource extends FreeMarkerPageResource {                  videos = (List<Map<String, Object>>) response.getMap().get("videos");              } -            // Get list of completed videos -            Map<String, Object> trainingRecord = null; -            Map<String, Object> completedVideos = new HashMap<String, Object>(); -            { -                JsonResponse response = backendGet("/accounts/" + mUserId + "/training"); -                if (response.getStatus().isSuccess()) { -                    trainingRecord = response.getMap(); -                    completedVideos = (Map<String, Object>) trainingRecord.get("videos"); -                } -            } -              // Mark the completed videos as completed              int chapterProgress = 0;              for (Map<String, Object> video : videos) { @@ -158,4 +172,16 @@ public class TrainingPageResource extends FreeMarkerPageResource {          return response;      } + +    int chapterIndex(String chapter) { +        if ("teacher".equals(chapter)) { +            return 4; +        } else if ("disciple".equals(chapter)) { +            return 3; +        } else if ("believer".equals(chapter)) { +            return 2; +        } else { +            return 1; +        } +    }  } | 
