Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r045ebfd1d11d9ed0a1f81a00abb1a2ea373e8d93 -r4972b394013bef3bc563652df80d9c2dbb04e238 --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 045ebfd1d11d9ed0a1f81a00abb1a2ea373e8d93) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 4972b394013bef3bc563652df80d9c2dbb04e238) @@ -809,4 +809,12 @@ audit.design.created=Learning design "{0}" ({1}) created by {2} ({3}) +authoring.tbl.desc.peer.review=These are the criteria for which the learners will rate each other using a 5 star rating. These fields are optional and no Peer Review will be created if they are left blank. +authoring.section.peerreview=Peer Review +authoring.label.peerrevice.criteria.num=Rating Criteria {0} +authoring.label.peerrevice.allow.comments=Allow learners to comment on other learners +authoring.label.peerrevice.min.words.in.comments=Minimum number of words in a comment +authoring.create.criteria=Create Criteria + + #======= End labels: Exported 732 labels for en AU ===== Index: lams_central/conf/language/lams/TBLResources.properties =================================================================== diff -u -rf7f38c0fd8e86323bca2df607731f1ec913e8869 -r4972b394013bef3bc563652df80d9c2dbb04e238 --- lams_central/conf/language/lams/TBLResources.properties (.../TBLResources.properties) (revision f7f38c0fd8e86323bca2df607731f1ec913e8869) +++ lams_central/conf/language/lams/TBLResources.properties (.../TBLResources.properties) (revision 4972b394013bef3bc563652df80d9c2dbb04e238) @@ -13,3 +13,5 @@ boilerplate.ae.application.exercise.num=Application Exercise {0} boilerplate.individual.reflection.title=Notebook boilerplate.individual.reflection.instructions=What are your key learning points? +boilerplate.peerreview=Peer Review +boilerplate.peerreview.instructions=Please rate your peers' interaction with the group. \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/authoring/template/PeerReviewCriteria.java =================================================================== diff -u --- lams_central/src/java/org/lamsfoundation/lams/authoring/template/PeerReviewCriteria.java (revision 0) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/template/PeerReviewCriteria.java (revision 4972b394013bef3bc563652df80d9c2dbb04e238) @@ -0,0 +1,101 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.authoring.template; + +import org.apache.tomcat.util.json.JSONException; +import org.apache.tomcat.util.json.JSONObject; +import org.lamsfoundation.lams.rating.model.RatingCriteria; + +/** Simple survey question used for parsing survey data before conversion to JSON */ +public class PeerReviewCriteria { + +// Defined in lams_common RatingCriteria +// public static final int TOOL_ACTIVITY_CRITERIA_TYPE = 1; +// public static final int AUTHORED_ITEM_CRITERIA_TYPE = 2; +// public static final int LEARNER_ITEM_CRITERIA_TYPE = 3; +// public static final int LESSON_CRITERIA_TYPE = 4; +// public static final int RATING_STYLE_COMMENT = 0; +// public static final int RATING_STYLE_STAR = 1; +// public static final int RATING_STYLE_RANKING = 2; +// public static final int RATING_STYLE_HEDGING = 3; +// public static final int RATING_STYLE_STAR_DEFAULT_MAX = 5; +// public static final int RATING_STYLE_RANKING_DEFAULT_MAX = 5; +// public static final int RATING_RANK_ALL = -1; + + private String title; + private Integer orderId; +// private Integer ratingCriteriaTypeId; + private Boolean commentsEnabled; // comments for RATING_STYLE_COMMENT, RATING_STYLE_STAR justification for RATING_STYLE_HEDGING + private Integer commentsMinWordsLimit; +// private Integer ratingStyle; // see comments above for RATING_STYLE +// private Integer maxRating; // see comments above for RATING_STYLE +// private Integer minimumRates; // Minimum number of people for whom one user may rate this criteria. Used for RATING_STYLE_STAR. +// private Integer maximumRates; // Minimum number of people for whom one user may rate this criteria. Used for RATING_STYLE_STAR. + + public PeerReviewCriteria(Integer orderId) { + this.orderId = orderId; + } + + public String getTitle() { + return title; + } + + public Integer getOrderId() { + return orderId; + } + + public Boolean getCommentsEnabled() { + return commentsEnabled; + } + + public Integer getCommentsMinWordsLimit() { + return commentsMinWordsLimit; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setOrderId(Integer orderId) { + this.orderId = orderId; + } + + public void setCommentsEnabled(Boolean commentsEnabled) { + this.commentsEnabled = commentsEnabled; + } + + public void setCommentsMinWordsLimit(Integer commentsMinWordsLimit) { + this.commentsMinWordsLimit = commentsMinWordsLimit; + } + + public JSONObject getAsJSONObject() throws JSONException { + JSONObject obj = new JSONObject().put("title", title).put("orderId", orderId) + .put("ratingStyle", RatingCriteria.RATING_STYLE_STAR) + .put("commentsEnabled", commentsEnabled != null ? commentsEnabled : false); + if ( commentsEnabled != null && commentsEnabled ) + obj.put("minWordsInComment", commentsMinWordsLimit != null ? commentsMinWordsLimit : 1); + return obj; + } + +} Index: lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateAction.java =================================================================== diff -u -rf7f38c0fd8e86323bca2df607731f1ec913e8869 -r4972b394013bef3bc563652df80d9c2dbb04e238 --- lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateAction.java (.../LdTemplateAction.java) (revision f7f38c0fd8e86323bca2df607731f1ec913e8869) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateAction.java (.../LdTemplateAction.java) (revision 4972b394013bef3bc563652df80d9c2dbb04e238) @@ -24,8 +24,10 @@ import java.io.File; import java.io.IOException; +import java.text.MessageFormat; import java.util.LinkedList; import java.util.List; +import java.util.ResourceBundle; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicInteger; @@ -47,8 +49,10 @@ import org.lamsfoundation.lams.authoring.service.IAuthoringService; import org.lamsfoundation.lams.authoring.template.AssessMCAnswer; import org.lamsfoundation.lams.authoring.template.Option; +import org.lamsfoundation.lams.authoring.template.TextUtil; import org.lamsfoundation.lams.learningdesign.Activity; import org.lamsfoundation.lams.learningdesign.GateActivity; +import org.lamsfoundation.lams.learningdesign.Grouping; import org.lamsfoundation.lams.learningdesign.LearningDesign; import org.lamsfoundation.lams.rest.RestTags; import org.lamsfoundation.lams.rest.ToolRestManager; @@ -121,6 +125,8 @@ protected static final String MINDMAP_ICON = "tool/lamind10/images/icon_mindmap.swf"; protected static final String VOTE_TOOL_SIGNATURE = "lavote11"; protected static final String VOTE_ICON = "tool/lavote11/images/icon_ranking.swf"; + protected static final String PEER_REVIEW_TOOL_SIGNATURE = "laprev11"; + protected static final String PEER_REVIEW_ICON = "tool/laprev11/images/icon_peerreview.svg"; protected static final String CHAT_SCRIBE_DESC = "Combined Chat and Scribe"; protected static final String FORUM_SCRIBE_DESC = "Combined Forum and Scribe"; @@ -172,23 +178,6 @@ return mapping.findForward("init"); } -// -// String responseBody = null; -// try { -// HttpResponse httpResponse = httpClient.execute(httpPost); -// int statusCode = httpResponse.getStatusLine().getStatusCode(); -// if (statusCode != HttpStatus.SC_OK) { -// LdTemplateAction.log.error("Error while calling REST servlet: " + url); -// return null; -// } -// responseBody = EntityUtils.toString(httpResponse.getEntity()); -// } finally { -// httpPost.releaseConnection(); -// } -// -// return new JSONObject(responseBody); -// } - protected abstract JSONObject createLearningDesign(HttpServletRequest request) throws Exception; @@ -255,7 +244,9 @@ } protected static final int rowHeightSpace = 100; - protected static final int activityWidthSpace = 150; + protected static final int activityWidthSpace = 185; + protected static final int gateHeightOffset = 5; + protected static final int gateWidthOffset = 50; /** * Calculate where to draw an activity. Aim for 4 activities per line. Returns Integer[x,y] @@ -292,6 +283,15 @@ return newPos; } + /** Work out the offset for a gate icon - different size to an ordinary icons */ + protected Integer[] calcGateOffset(Integer[] currPos) { + Integer[] newPos = new Integer[2]; + newPos[1] = currPos[1] + gateHeightOffset; + newPos[0] = currPos[0] + gateWidthOffset; + return newPos; + } + + /** * Create a unique title for this learning design, within the right length for the database. The title will * be __UniqueDate, where the userEnteredString is capitalised and @@ -384,7 +384,8 @@ /** Create a group activity's JSON objects */ protected JSONObject[] createGroupingActivity(AtomicInteger uiid, int order, Integer[] layoutCoords, - Integer groupingTypeID, Integer numLearners, Integer numGroups, String title, String[] groupNames) + Integer groupingTypeID, Integer numLearners, Integer numGroups, String title, String[] groupNames, + ResourceBundle appBundle, MessageFormat formatter) throws JSONException { JSONObject[] responseJSONs = new JSONObject[2]; @@ -393,22 +394,37 @@ int groupingUIID = uiid.incrementAndGet(); groupingJSON.put(AuthoringJsonTags.GROUPING_UIID, groupingUIID); groupingJSON.put(AuthoringJsonTags.GROUPING_TYPE_ID, groupingTypeID); - groupingJSON.put(AuthoringJsonTags.NUMBER_OF_GROUPS, numGroups); + if ( groupingTypeID.equals(Grouping.CHOSEN_GROUPING_TYPE) ) { + groupingJSON.put(AuthoringJsonTags.MAX_NUMBER_OF_GROUPS, numGroups); + } else { + groupingJSON.put(AuthoringJsonTags.NUMBER_OF_GROUPS, numGroups); + } groupingJSON.put(AuthoringJsonTags.LEARNERS_PER_GROUP, numLearners); groupingJSON.put(AuthoringJsonTags.EQUAL_NUMBER_OF_LEARNERS_PER_GROUP, Boolean.FALSE); - int orderId = 0; + // mimic what Authoring is doing for the group name creations + JSONArray groups = new JSONArray(); if (groupNames != null) { - JSONArray groups = new JSONArray(); + int orderId = 0; for (String groupName : groupNames) { JSONObject group = new JSONObject(); group.put(AuthoringJsonTags.GROUP_NAME, groupName); group.put(AuthoringJsonTags.ORDER_ID, orderId++); group.put(AuthoringJsonTags.GROUP_UIID, uiid.incrementAndGet()); groups.put(group); } - groupingJSON.put(AuthoringJsonTags.GROUPS, groups); - } + } else { + Integer useNumGroups = ( numGroups != null && numGroups > 0) ? numGroups : 2; + for ( int orderId = 0, groupNum = 1; orderId < useNumGroups; orderId++, groupNum++ ) { + JSONObject group = new JSONObject(); + group.put(AuthoringJsonTags.GROUP_NAME, + TextUtil.getText(appBundle, formatter, "label.course.groups.prefix", null) + groupNum); + group.put(AuthoringJsonTags.ORDER_ID, orderId); + group.put(AuthoringJsonTags.GROUP_UIID, uiid.incrementAndGet()); + groups.put(group); + } + } + groupingJSON.put(AuthoringJsonTags.GROUPS, groups); Integer[] pos = layoutCoords != null ? layoutCoords : calcPosition(order); @@ -1258,6 +1274,38 @@ LdTemplateAction.WIKI_ICON, toolContentID, contentFolderID, groupingUIID, parentUIID, parentActivityType, activityTitle != null ? activityTitle : "Wiki", Activity.CATEGORY_COLLABORATION); } + + /** + * Helper method to create a Peer Review tool content. + * Required fields in toolContentJSON: "title", "instructions", "questions", "firstName", "lastName", "lastName", + * "questions" and "references". + * + * The criterias entry should be JSONArray as defined in PeerReviewCriters object. + */ + protected Long createPeerReviewToolContent(UserDTO user, String title, String instructions, + String reflectionInstructions, JSONArray criterias) + throws JSONException, HttpException, IOException { + + JSONObject toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, null, null, + user); + toolContentJSON.put("criterias", criterias); + return createToolContent(user, LdTemplateAction.PEER_REVIEW_TOOL_SIGNATURE, toolContentJSON); + } + + /** + * Creates a PeerRev activity's JSON details. + */ + protected JSONObject createPeerReviewActivity(AtomicInteger uiid, int order, Integer[] layoutCoords, + Long toolContentID, String contentFolderID, Integer groupingUIID, Integer parentUIID, + Integer parentActivityType, String activityTitle) throws JSONException { + + return createToolActivity(uiid, order, layoutCoords, LdTemplateAction.PEER_REVIEW_TOOL_SIGNATURE, + LdTemplateAction.PEER_REVIEW_ICON, toolContentID, contentFolderID, groupingUIID, parentUIID, + parentActivityType, activityTitle != null ? activityTitle : "Peer Review", Activity.CATEGORY_CONTENT); + } + + /** + /* ************************************** Service related methods ********************************************** */ /* ************************************** I18N related methods ************************************************* */ @@ -1396,7 +1444,6 @@ TreeMap optionsMap = getOptions(request, questionNumber); // reorder the options and setup the return value LinkedList