Index: lams_tool_preview/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -rc260f6f3f855894e54d3725095e56d39a139d893 -r24b187a7aa86f8975f9d4fabab3e7c2d03e33229 --- lams_tool_preview/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision c260f6f3f855894e54d3725095e56d39a139d893) +++ lams_tool_preview/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 24b187a7aa86f8975f9d4fabab3e7c2d03e33229) @@ -144,4 +144,11 @@ event.sent.results.no.results=No results msg.results.sent={0} Email(s) Sent button.email.results=Email Results -label.notify.user.of.results=Notify Users of Results \ No newline at end of file +label.notify.user.of.results=Notify Users of Results +label.number.of.team.members=No of team members +label.average=Average +label.for.user=For {0} +label.learner=Student +label.spa.factor=SPA factor +label.total.group.mark=Total team mark +label.individual.mark=Individual mark \ No newline at end of file Index: lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/service/IPeerreviewService.java =================================================================== diff -u -r0a6765ac7eb73c6b99c343a021877c48236241b8 -r24b187a7aa86f8975f9d4fabab3e7c2d03e33229 --- lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/service/IPeerreviewService.java (.../IPeerreviewService.java) (revision 0a6765ac7eb73c6b99c343a021877c48236241b8) +++ lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/service/IPeerreviewService.java (.../IPeerreviewService.java) (revision 24b187a7aa86f8975f9d4fabab3e7c2d03e33229) @@ -24,6 +24,7 @@ package org.lamsfoundation.lams.tool.peerreview.service; import java.util.Collection; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -39,6 +40,7 @@ import org.lamsfoundation.lams.tool.peerreview.model.Peerreview; import org.lamsfoundation.lams.tool.peerreview.model.PeerreviewSession; import org.lamsfoundation.lams.tool.peerreview.model.PeerreviewUser; +import org.lamsfoundation.lams.util.ExcelCell; /** * Interface that defines the contract that all Peerreview service provider must follow. @@ -276,4 +278,6 @@ /** Send an email with the user's results to the specified user in the session */ int emailReportToUser(Long toolContentId, Long sessionId, Long userId); + /** Spreadsheet */ + LinkedHashMap exportTeamReportSpreadsheet(Long toolContentId); } Index: lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/service/PeerreviewServiceImpl.java =================================================================== diff -u -r2cad2462df185fce685da61762fb06d98ebee415 -r24b187a7aa86f8975f9d4fabab3e7c2d03e33229 --- lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/service/PeerreviewServiceImpl.java (.../PeerreviewServiceImpl.java) (revision 2cad2462df185fce685da61762fb06d98ebee415) +++ lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/service/PeerreviewServiceImpl.java (.../PeerreviewServiceImpl.java) (revision 24b187a7aa86f8975f9d4fabab3e7c2d03e33229) @@ -23,13 +23,13 @@ package org.lamsfoundation.lams.tool.peerreview.service; -import java.security.InvalidParameterException; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -45,7 +45,6 @@ import org.apache.tomcat.util.json.JSONArray; import org.apache.tomcat.util.json.JSONException; import org.apache.tomcat.util.json.JSONObject; -import org.lamsfoundation.lams.events.AbstractDeliveryMethod; import org.lamsfoundation.lams.events.IEventNotificationService; import org.lamsfoundation.lams.learning.service.ILearnerService; import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; @@ -79,10 +78,12 @@ import org.lamsfoundation.lams.tool.peerreview.model.PeerreviewSession; import org.lamsfoundation.lams.tool.peerreview.model.PeerreviewUser; import org.lamsfoundation.lams.tool.peerreview.util.PeerreviewToolContentHandler; +import org.lamsfoundation.lams.tool.peerreview.util.SpreadsheetBuilder; import org.lamsfoundation.lams.tool.service.ILamsToolService; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.ExcelCell; import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; @@ -546,6 +547,22 @@ } notificationMessage.append("\n"); } + + @Override + @SuppressWarnings("unchecked") + public LinkedHashMap exportTeamReportSpreadsheet(Long toolContentId) { + + Peerreview peerreview = peerreviewDao.getByContentId(toolContentId); + if (peerreview == null) { + PeerreviewServiceImpl.log.warn("Did not find activity with toolContentId: " + toolContentId + " to remove learner content"); + return null; + } + + return new SpreadsheetBuilder(peerreview, ratingService, peerreviewSessionDao, peerreviewUserDao, this).generateTeamReport(); + + } + + // ***************************************************************************** // private methods // ***************************************************************************** Index: lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/util/SpreadsheetBuilder.java =================================================================== diff -u --- lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/util/SpreadsheetBuilder.java (revision 0) +++ lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/util/SpreadsheetBuilder.java (revision 24b187a7aa86f8975f9d4fabab3e7c2d03e33229) @@ -0,0 +1,254 @@ +package org.lamsfoundation.lams.tool.peerreview.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.lamsfoundation.lams.rating.dto.ItemRatingCriteriaDTO; +import org.lamsfoundation.lams.rating.dto.ItemRatingDTO; +import org.lamsfoundation.lams.rating.model.RatingCriteria; +import org.lamsfoundation.lams.rating.service.IRatingService; +import org.lamsfoundation.lams.tool.peerreview.dao.PeerreviewSessionDAO; +import org.lamsfoundation.lams.tool.peerreview.dao.PeerreviewUserDAO; +import org.lamsfoundation.lams.tool.peerreview.model.Peerreview; +import org.lamsfoundation.lams.tool.peerreview.model.PeerreviewSession; +import org.lamsfoundation.lams.tool.peerreview.model.PeerreviewUser; +import org.lamsfoundation.lams.tool.peerreview.service.IPeerreviewService; +import org.lamsfoundation.lams.util.ExcelCell; +import org.springframework.util.StringUtils; + +/** Creates a Spreadsheet that reports the averages, with each team/group shown on a separate worksheet. + * Calculates averages for each rating and for each user. The SPA factor then calculates the user's overall average + * against the team average. + * Has a empty Mark column so that the teacher can add a manual mark if they want. + */ +public class SpreadsheetBuilder { + + private static final ExcelCell[] EMPTY_ROW = new ExcelCell[4]; + + private Peerreview peerreview; + private IRatingService ratingService; + private List criterias; + private PeerreviewSessionDAO peerreviewSessionDao; + private PeerreviewUserDAO peerreviewUserDao; + private IPeerreviewService service; + + private LinkedHashMap dataToExport; + + // processing details set up when header is created, then used for each session + private ExcelCell[] titleRow; + private int countNonCommentCriteria = 0; + private int fullColumnCount = 0; + private int averageColumnIndex = 0; + private Map criteriaOffset; + + + public SpreadsheetBuilder(Peerreview peerreview, IRatingService ratingService, PeerreviewSessionDAO peerreviewSessionDao, + PeerreviewUserDAO peerreviewUserDao, IPeerreviewService service) { + this.peerreview = peerreview; + this.ratingService = ratingService; + this.peerreviewSessionDao = peerreviewSessionDao; + this.peerreviewUserDao = peerreviewUserDao; + this.service = service; + } + + public LinkedHashMap generateTeamReport() { + + // this one is guaranteed to give a consistent order over peerreview.getRatingCriterias() + criterias = ratingService.getCriteriasByToolContentId(peerreview.getContentId()); + + dataToExport = new LinkedHashMap(); + + titleRow = generateWorksheetHeading(criterias); + + List sessions = peerreviewSessionDao.getByContentId(peerreview.getContentId()); + for (PeerreviewSession session : sessions) { + List rowList = generateTeamWorksheet(session); + ExcelCell[][] worksheetData = rowList.toArray(new ExcelCell[][] {}); + dataToExport.put(session.getSessionName(), worksheetData); + } + + + return dataToExport; + } + + private List generateTeamWorksheet(PeerreviewSession session) { + + List rowList = new LinkedList(); + rowList.add(titleRow); + + List users = peerreviewUserDao.getBySessionID(session.getSessionId()); + Map userNames = new TreeMap(); + for (PeerreviewUser user : users) { + userNames.put(user.getUserId(), StringEscapeUtils.escapeCsv(user.getFirstName() + " " + user.getLastName())); + } + + Map userRowMap = new HashMap(); + + ExcelCell[] userRow = new ExcelCell[2]; + userRow[0] = new ExcelCell(service.getLocalisedMessage("label.number.of.team.members", null), true); + userRow[1] = new ExcelCell(users.size(), IndexedColors.YELLOW); + rowList.add(userRow); + + rowList.add(EMPTY_ROW); + + // uses same index as the user row, so allow for the name in the first column + Double[] criteriaMarkSum = new Double[countNonCommentCriteria+1]; + Integer[] criteriaMarkCount = new Integer[countNonCommentCriteria+1]; + for (int index = 1; index < criteriaMarkSum.length; index++) { + criteriaMarkSum[index] = 0D; + criteriaMarkCount[index] = 0; + } + + // Process all the criterias and build up rows for each rated user. Store in temporary map. + List ratingDtos = service.getRatingCriteriaDtos(session.getPeerreview().getContentId(), + userNames.keySet(), true, -1L); + for (ItemRatingDTO ratingDto : ratingDtos) { + Double userMarkSum = 0D; + userRow = new ExcelCell[fullColumnCount]; + + for (ItemRatingCriteriaDTO cDto : ratingDto.getCriteriaDtos()) { + if (cDto.getAverageRatingAsNumber() != null && ! cDto.getAverageRatingAsNumber().equals(0)) { + Integer criteriaIndex = criteriaOffset.get(cDto.getRatingCriteria().getRatingCriteriaId()); + double db = cDto.getAverageRatingAsNumber().doubleValue(); + userRow[criteriaIndex] = new ExcelCell(roundTo2Places(db), false); + criteriaMarkSum[criteriaIndex] += db; + criteriaMarkCount[criteriaIndex] = criteriaMarkCount[criteriaIndex] + 1; + userMarkSum += db; + } + } + + userRow[averageColumnIndex] = new ExcelCell(countNonCommentCriteria > 0 ? roundTo2Places(userMarkSum / countNonCommentCriteria) : 0D, true); + userRowMap.put(ratingDto.getItemId(), userRow); + } + + // calculate the group averages + ExcelCell[] avgRow = new ExcelCell[fullColumnCount]; + avgRow[0] = new ExcelCell(service.getLocalisedMessage("label.average", null), true); + Double averageMarkSum = 0D; + for (int index = 1; index < criteriaMarkSum.length; index++) { + if ( criteriaMarkCount[index] > 0 ) { + Double d = criteriaMarkSum[index] / criteriaMarkCount[index]; + avgRow[index] = new ExcelCell(roundTo2Places(d), true); + averageMarkSum += d; + } + } + Double finalGroupAverage = countNonCommentCriteria > 0 ? roundTo2Places(averageMarkSum / countNonCommentCriteria) : 0D; + avgRow[averageColumnIndex] = new ExcelCell(finalGroupAverage, true); + + // Combine rated rows with rows with users not yet rated, to make up complete list, and write out to rowList. + for (PeerreviewUser user : users) { + userRow = userRowMap.get(user.getUserId()); + if (userRow == null) { + userRow = new ExcelCell[fullColumnCount]; + } else { + ExcelCell averageCell = userRow[averageColumnIndex]; + Double learnerAverage = (Double) averageCell.getCellValue(); + Double spa = countNonCommentCriteria > 0 ? roundTo2Places(learnerAverage / finalGroupAverage): 0D; + userRow[averageColumnIndex+1] = new ExcelCell(spa, true); + userRow[averageColumnIndex+2] = new ExcelCell("", IndexedColors.YELLOW); + userRow[averageColumnIndex+3] = new ExcelCell("", IndexedColors.GREEN); + } + userRow[0] = new ExcelCell(userNames.get(user.getUserId()), false); + rowList.add(userRow); + } + + // Learners marks done, write out the group average + rowList.add(avgRow); + + // now do all the comments + for ( RatingCriteria criteria : criterias ) { + if ( criteria.isCommentsEnabled() ) { + rowList.add(EMPTY_ROW); + rowList.add(EMPTY_ROW); + userRow = new ExcelCell[1]; + userRow[0] = new ExcelCell(criteria.getTitle(), true); + rowList.add(userRow); + + if ( criteria.isHedgeStyleRating() ) { + // just need the first entry as it is the same for everyone - the justification + if ( users.size() > 0 ) { + generateUsersComments(session, rowList, userNames, criteria, users.get(0), false); + } + } else { + for ( PeerreviewUser user : users ) { + generateUsersComments(session, rowList, userNames, criteria, user, true); + } + } + } + } + + return rowList; + } + + private void generateUsersComments(PeerreviewSession session, List rowList, + Map userNames, RatingCriteria criteria, PeerreviewUser user, boolean showForName) { + + List commentRowList = new LinkedList(); + List comments = peerreviewUserDao.getDetailedRatingsComments(session.getPeerreview().getContentId(), + session.getSessionId(), criteria.getRatingCriteriaId(), user.getUserId()); + for (Object[] comment : comments) { + if (comment[1] != null) { + ExcelCell[] commentRow = new ExcelCell[2]; + commentRow[0] = new ExcelCell(userNames.get(((BigInteger) comment[0]).longValue()), false); + commentRow[1] = new ExcelCell(StringUtils.replace((String) comment[1], "
", "\n"), false); + commentRowList.add(commentRow); + } + } + + if (commentRowList.size() > 0) { + + rowList.add(EMPTY_ROW); + + if (showForName) { + ExcelCell[] userRow = new ExcelCell[1]; + userRow[0] = new ExcelCell(service.getLocalisedMessage("label.for.user", + new Object[] { userNames.get(user.getUserId()) }), false); + rowList.add(userRow); + } + + rowList.addAll(commentRowList); + } + + } + + private double roundTo2Places(double d) { + BigDecimal bd = new BigDecimal(d); + bd = bd.setScale(2, RoundingMode.HALF_UP); + return bd.doubleValue(); + } + + private ExcelCell[] generateWorksheetHeading(List criterias) { + ExcelCell[] titleRow = new ExcelCell[criterias.size() + 5]; + titleRow[0] = new ExcelCell(service.getLocalisedMessage("label.learner", null), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + int index = 1; + + criteriaOffset = new HashMap(); + + for ( RatingCriteria criteria : criterias ) { + if ( ! criteria.isCommentRating() ) { + titleRow[index] = new ExcelCell(criteria.getTitle(), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + criteriaOffset.put(criteria.getRatingCriteriaId(), index); + countNonCommentCriteria++; + index++; + } + } + averageColumnIndex = index; + + titleRow[index++] = new ExcelCell(service.getLocalisedMessage("label.average", null), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + titleRow[index++] = new ExcelCell(service.getLocalisedMessage("label.spa.factor", null), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + titleRow[index++] = new ExcelCell(service.getLocalisedMessage("label.total.group.mark", null), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + titleRow[index++] = new ExcelCell(service.getLocalisedMessage("label.individual.mark", null), true, ExcelCell.BORDER_STYLE_BOTTOM_THIN); + fullColumnCount = index; + + return titleRow; + } +} Index: lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/web/action/MonitoringAction.java =================================================================== diff -u -r0a6765ac7eb73c6b99c343a021877c48236241b8 -r24b187a7aa86f8975f9d4fabab3e7c2d03e33229 --- lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/web/action/MonitoringAction.java (.../MonitoringAction.java) (revision 0a6765ac7eb73c6b99c343a021877c48236241b8) +++ lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/web/action/MonitoringAction.java (.../MonitoringAction.java) (revision 24b187a7aa86f8975f9d4fabab3e7c2d03e33229) @@ -29,10 +29,13 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.TimeZone; import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -52,6 +55,9 @@ import org.lamsfoundation.lams.tool.peerreview.model.PeerreviewUser; import org.lamsfoundation.lams.tool.peerreview.service.IPeerreviewService; import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.ExcelCell; +import org.lamsfoundation.lams.util.ExcelUtil; +import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.util.AttributeNames; import org.lamsfoundation.lams.web.util.SessionMap; @@ -97,7 +103,9 @@ if (param.equals("sendResultsToSessionUsers")) { return sendResultsToSessionUsers(mapping, form, request, response); } - + if ( param.equals("exportTeamReport")) { + return exportTeamReport(mapping, form, request, response); + } return mapping.findForward(PeerreviewConstants.ERROR); } @@ -514,6 +522,55 @@ return null; } + + /** + * Exports Team Report into Excel spreadsheet. + * @throws ServletException + * @throws IOException + */ + public ActionForward exportTeamReport(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException { + + IPeerreviewService service = getPeerreviewService(); + Long toolContentId = WebUtil.readLongParam(request, PeerreviewConstants.ATTR_TOOL_CONTENT_ID); + + Peerreview peerreview = service.getPeerreviewByContentId(toolContentId); + if (peerreview == null) { + log.warn("Did not find Peer Review with toolContentId: " + toolContentId + " export content"); + return null; + } + + String fileName = peerreview.getTitle().replaceAll(" ", "_") + ".xlsx"; + + try { + fileName = FileUtil.encodeFilenameForDownload(request, fileName); + + if (log.isDebugEnabled()) { + log.debug("Exporting to a spreadsheet for toolContentId: " + toolContentId + "filename "+fileName); + } + + response.setContentType("application/x-download"); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName); + ServletOutputStream out = response.getOutputStream(); + + LinkedHashMap dataToExport = service.exportTeamReportSpreadsheet(toolContentId); + + // set cookie that will tell JS script that export has been finished + String downloadTokenValue = WebUtil.readStrParam(request, "downloadTokenValue"); + Cookie fileDownloadTokenCookie = new Cookie("fileDownloadToken", downloadTokenValue); + fileDownloadTokenCookie.setPath("/"); + response.addCookie(fileDownloadTokenCookie); + + ExcelUtil.createExcel(out, dataToExport, "Exported on:", true); + + } catch (IOException e) { + log.error("exportTeamReportExcelSpreadsheet i/o error occured: "+e.getMessage(), e); + throw new ServletException(e); + } + + return null; + } + // ************************************************************************************* // Private method // ************************************************************************************* Index: lams_tool_preview/web/WEB-INF/struts-config.xml =================================================================== diff -u -rdbc01e6417b9ebbe49741ddd0463c571cc6e3932 -r24b187a7aa86f8975f9d4fabab3e7c2d03e33229 --- lams_tool_preview/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision dbc01e6417b9ebbe49741ddd0463c571cc6e3932) +++ lams_tool_preview/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 24b187a7aa86f8975f9d4fabab3e7c2d03e33229) @@ -208,7 +208,10 @@ type="org.lamsfoundation.lams.tool.peerreview.web.action.MonitoringAction" parameter="sendResultsToSessionUsers" > - + + Index: lams_tool_preview/web/pages/monitoring/summary.jsp =================================================================== diff -u -racdd430979cfa7711b762f950fdca4b3a40335a2 -r24b187a7aa86f8975f9d4fabab3e7c2d03e33229 --- lams_tool_preview/web/pages/monitoring/summary.jsp (.../summary.jsp) (revision acdd430979cfa7711b762f950fdca4b3a40335a2) +++ lams_tool_preview/web/pages/monitoring/summary.jsp (.../summary.jsp) (revision 24b187a7aa86f8975f9d4fabab3e7c2d03e33229) @@ -1,13 +1,17 @@ <%@ include file="/common/taglibs.jsp"%> + + - + + + @@ -65,6 +96,12 @@
+ + @@ -103,19 +140,19 @@ -
 
-
+
+ reflections.do?sessionMapID=${sessionMapID}&toolSessionId=${groupSummary.sessionId}&toolContentID=${sessionMap.toolContentID} - - + + loffset5 - +