Index: idea_project/.idea/.name =================================================================== diff -u -r399094fd7734e7d5bed9bd9a40ca4a463ff02b35 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- idea_project/.idea/.name (.../.name) (revision 399094fd7734e7d5bed9bd9a40ca4a463ff02b35) +++ idea_project/.idea/.name (.../.name) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -1 +1 @@ -LAMS \ No newline at end of file +LAMS 4.7 \ No newline at end of file Index: idea_project/.idea/misc.xml =================================================================== diff -u -r10ada76a9a401c0fb4842e107613be3ffcc8430b -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- idea_project/.idea/misc.xml (.../misc.xml) (revision 10ada76a9a401c0fb4842e107613be3ffcc8430b) +++ idea_project/.idea/misc.xml (.../misc.xml) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -1,8 +1,8 @@ - - + + @@ -11,4 +11,7 @@ + + \ No newline at end of file Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r1e85a36d6397d66fa9cc46b334e2ef2bef8af4f6 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 1e85a36d6397d66fa9cc46b334e2ef2bef8af4f6) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -835,6 +835,7 @@ authoring.label.grouping.learners.choice = Learner's Choice authoring.label.grouping.teachers.choice = Teacher's Choice authoring.label.grouping.random.allocation = Random Allocation +authoring.label.question.collection = Put new questions into following Question Bank collection authoring.label.numgroups = Number of teams: authoring.error.numgroups = Number of teams must be 1 to 99. authoring.label.numlearners = Number of learners: @@ -891,6 +892,8 @@ authoring.fla.input.detached.error = Activity "{0}" had an input activity that is missing or is not one of previous activities. Input was cleared. label.question.not.added = This question has already been added label.questions.choice.collection = Choose a collection: +label.questions.choice.collection.new.option = +label.questions.choice.collection.new.prompt = Enter a name for the new collection: authoring.fla.branch.mapping.ordered.asc = Start with branches mapped to highest ordered answers title.import.instruction.antivirus = An antivirus scan will be performed. It can take a while. outcome.authoring.create.new = [create new] @@ -1144,4 +1147,4 @@ index.organisation.link.tooltip = Copy direct access course URL to clipboard index.organisation.link.success = Course URL copied to clipboard authoring.tbl.shuffle.questions = Shuffle question order in iRAT -authoring.tbl.shuffle.questions.tooltip = Shuffles the order of questions in the iRAT for all students. In the tRAT the order of question will be the same for all students. +authoring.tbl.shuffle.questions.tooltip = Shuffles the order of questions in the iRAT for all students. In the tRAT the order of question will be the same for all students. \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/QbCollectionController.java =================================================================== diff -u -re7cbf85417c8226f95995e5adb34f7eeb386a98c -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_central/src/java/org/lamsfoundation/lams/web/qb/QbCollectionController.java (.../QbCollectionController.java) (revision e7cbf85417c8226f95995e5adb34f7eeb386a98c) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/QbCollectionController.java (.../QbCollectionController.java) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -22,32 +22,21 @@ package org.lamsfoundation.lams.web.qb; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.outcome.service.IOutcomeService; import org.lamsfoundation.lams.qb.model.QbCollection; import org.lamsfoundation.lams.qb.model.QbQuestion; import org.lamsfoundation.lams.qb.service.IQbService; import org.lamsfoundation.lams.security.ISecurityService; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; -import org.lamsfoundation.lams.util.CommonConstants; -import org.lamsfoundation.lams.util.Configuration; -import org.lamsfoundation.lams.util.ConfigurationKeys; -import org.lamsfoundation.lams.util.MessageService; -import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.util.*; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @@ -57,6 +46,15 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + @Controller @RequestMapping("/qb/collection") public class QbCollectionController { @@ -186,13 +184,26 @@ qbService.addQuestionToCollection(targetCollectionUid, qbQuestionId, copy); } - @RequestMapping(path = "/addCollection", method = RequestMethod.POST) + @RequestMapping(path = "/addCollection", method = RequestMethod.POST, produces = "text/plain") @ResponseBody - public void addCollection(@RequestParam String name) { + public ResponseEntity addCollection(@RequestParam String name) { + if (StringUtils.isBlank(name)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Name is required for creating a new collection"); + } if (!Configuration.getAsBoolean(ConfigurationKeys.QB_COLLECTIONS_CREATE_ALLOW)) { - throw new SecurityException("New collections are disabled"); + log.error("Trying to create a new collection when it is disabled: " + name); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Creating QB collections is disabled"); } - qbService.addCollection(getUserId(), name); + String trimmedName = name.strip(); + boolean nameAlreadyExists = qbService.getUserCollections(getUserId()).stream().map(QbCollection::getName) + .anyMatch(collectionName -> collectionName.equalsIgnoreCase(trimmedName)); + if (nameAlreadyExists) { + return ResponseEntity.status(HttpStatus.FORBIDDEN) + .body(messageService.getMessage("label.qb.collection.name.duplicate.error")); + } + + QbCollection collection = qbService.addCollection(getUserId(), trimmedName); + return ResponseEntity.ok(collection.getUid().toString()); } @RequestMapping(path = "/changeCollectionName", method = RequestMethod.POST) @@ -277,15 +288,13 @@ rowElement.setAttribute(CommonConstants.ELEMENT_ID, uid); // the last cell is for creating stats button - String usage = !view.equalsIgnoreCase("list") ? String.valueOf( - view.equalsIgnoreCase("version") ? qbService.getCountQuestionActivitiesByUid(question.getUid()) - : qbService.getCountQuestionActivitiesByQuestionId(question.getQuestionId())) - : null; + String usage = !view.equalsIgnoreCase("list") ? String.valueOf(view.equalsIgnoreCase("version") + ? qbService.getCountQuestionActivitiesByUid(question.getUid()) + : qbService.getCountQuestionActivitiesByQuestionId(question.getQuestionId())) : null; boolean hasVersions = qbService.countQuestionVersions(question.getQuestionId()) > 1; - String learningOutcomes = view.equalsIgnoreCase("single") - ? outcomeService.getOutcomeMappings(null, null, null, question.getQuestionId()).stream() - .map(m -> m.getOutcome().getName()).collect(Collectors.joining("
")) - : null; + String learningOutcomes = view.equalsIgnoreCase("single") ? outcomeService.getOutcomeMappings(null, + null, null, question.getQuestionId()).stream().map(m -> m.getOutcome().getName()) + .collect(Collectors.joining("
")) : null; String[] data = { question.getQuestionId().toString(), WebUtil.removeHTMLtags(question.getName()).trim(), Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js =================================================================== diff -u -r3b73fca4dac9dbd51f0b319791e477683203073c -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 3b73fca4dac9dbd51f0b319791e477683203073c) +++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -1,4 +1,4 @@ -/** +/** * This file contains main methods for Authoring. */ @@ -1343,7 +1343,7 @@ var activity = null; if (!onlyDetachedLeft) { $.each(activitiesCopy, function(){ - if (this.transitions.to.length > 0) { + if (this.transitions && this.transitions.to.length > 0) { activity = this; // crawl back using "to" transition all the way to the beggining of sequence while (activity.transitions.to.length > 0) { @@ -3449,4 +3449,4 @@ var snapped = Snap.snapTo(layout.snapToGrid.step, input, layout.snapToGrid.step / 2); return skipPadding ? snapped : Math.max(snapped, layout.snapToGrid.padding); } -}; +}; \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java =================================================================== diff -u -r0564c1523e752ef571fba78132a42a5085e06643 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java (.../UserManagementService.java) (revision 0564c1523e752ef571fba78132a42a5085e06643) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/service/UserManagementService.java (.../UserManagementService.java) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -23,28 +23,6 @@ package org.lamsfoundation.lams.usermanagement.service; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.UUID; -import java.util.Vector; -import java.util.stream.Collectors; - import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.lamsfoundation.lams.contentrepository.NodeKey; @@ -54,32 +32,15 @@ import org.lamsfoundation.lams.logevent.LogEvent; import org.lamsfoundation.lams.logevent.service.ILogEventService; import org.lamsfoundation.lams.themes.Theme; -import org.lamsfoundation.lams.usermanagement.FavoriteOrganisation; -import org.lamsfoundation.lams.usermanagement.ForgotPasswordRequest; -import org.lamsfoundation.lams.usermanagement.IUserDAO; -import org.lamsfoundation.lams.usermanagement.Organisation; -import org.lamsfoundation.lams.usermanagement.OrganisationGroup; -import org.lamsfoundation.lams.usermanagement.OrganisationGrouping; -import org.lamsfoundation.lams.usermanagement.OrganisationType; -import org.lamsfoundation.lams.usermanagement.Role; -import org.lamsfoundation.lams.usermanagement.User; -import org.lamsfoundation.lams.usermanagement.UserOrganisation; -import org.lamsfoundation.lams.usermanagement.UserOrganisationCollapsed; -import org.lamsfoundation.lams.usermanagement.UserOrganisationRole; -import org.lamsfoundation.lams.usermanagement.WorkspaceFolder; +import org.lamsfoundation.lams.usermanagement.*; import org.lamsfoundation.lams.usermanagement.dao.IFavoriteOrganisationDAO; import org.lamsfoundation.lams.usermanagement.dao.IOrganisationDAO; import org.lamsfoundation.lams.usermanagement.dao.IRoleDAO; import org.lamsfoundation.lams.usermanagement.dao.IUserOrganisationDAO; import org.lamsfoundation.lams.usermanagement.dto.OrganisationDTO; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.dto.UserManageBean; -import org.lamsfoundation.lams.util.CommonConstants; -import org.lamsfoundation.lams.util.Configuration; -import org.lamsfoundation.lams.util.ConfigurationKeys; -import org.lamsfoundation.lams.util.HashUtil; -import org.lamsfoundation.lams.util.LanguageUtil; -import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.*; import org.lamsfoundation.lams.util.imgscalr.ResizePictureUtil; import org.lamsfoundation.lams.web.filter.AuditLogFilter; import org.lamsfoundation.lams.web.session.SessionManager; @@ -88,6 +49,11 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import java.io.*; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + /** *

* View Source @@ -288,8 +254,9 @@ } // it's ugly to put query string here, but it is a convention of this class so let's stick to it for now - String query = "SELECT uo.user FROM UserOrganisation uo INNER JOIN uo.userOrganisationRoles r WHERE uo.organisation.organisationId=" - + organisationID + " AND r.role.name= '" + roleName + "'"; + String query = + "SELECT uo.user FROM UserOrganisation uo INNER JOIN uo.userOrganisationRoles r WHERE uo.organisation.organisationId=" + + organisationID + " AND r.role.name= '" + roleName + "'"; List queryResult = baseDAO.find(query); for (User user : queryResult) { @@ -604,8 +571,9 @@ // get i18n'd message according to server locale String[] tokenisedLocale = LanguageUtil.getDefaultLangCountry(); Locale serverLocale = new Locale(tokenisedLocale[0], tokenisedLocale[1]); - String runSeqName = messageService.getMessageSource().getMessage( - UserManagementService.SEQUENCES_FOLDER_NAME_KEY, new Object[] { workspaceName }, serverLocale); + String runSeqName = messageService.getMessageSource() + .getMessage(UserManagementService.SEQUENCES_FOLDER_NAME_KEY, new Object[] { workspaceName }, + serverLocale); if ((runSeqName != null) && runSeqName.startsWith("???")) { log.warn("Problem in the language file - can't find an entry for " @@ -757,13 +725,6 @@ log.debug("added " + user.getLogin() + " to " + org.getName()); } - // if user is to be added to a class, make user a member of parent - // course also if not already - if (org.getOrganisationType().getOrganisationTypeId().equals(OrganisationType.CLASS_TYPE) - && (getUserOrganisation(user.getUserId(), org.getParentOrganisation().getOrganisationId()) == null)) { - setRolesForUserOrganisation(user, org.getParentOrganisation(), rolesList, checkGroupManagerRoles); - } - List rolesCopy = new ArrayList<>(); rolesCopy.addAll(rolesList); log.debug("rolesList.size: " + rolesList.size()); @@ -822,6 +783,17 @@ // make sure group managers have monitor in each subgroup checkGroupManager(user, org); } + + // if user is to be added to a class, make user a member of parent + // course also if not already + if (org.getOrganisationType().getOrganisationTypeId().equals(OrganisationType.CLASS_TYPE)) { + Set parentOrganisationRoleSet = getUserOrganisationRoles( + org.getParentOrganisation().getOrganisationId(), user.getLogin()).stream() + .map(uor -> uor.getRole().getRoleId().toString()).collect(Collectors.toSet()); + parentOrganisationRoleSet.addAll(rolesList); + setRolesForUserOrganisation(user, org.getParentOrganisation(), new ArrayList<>(parentOrganisationRoleSet), + checkGroupManagerRoles); + } } private void checkGroupManager(User user, Organisation org) { @@ -876,8 +848,8 @@ UserOrganisationRole uor = new UserOrganisationRole(uo, role); save(uor); uo.addUserOrganisationRole(uor); - log.debug("setting role: " + uor.getRole().getName() + " in organisation: " - + uor.getUserOrganisation().getOrganisation().getName()); + log.debug("setting role: " + uor.getRole().getName() + " in organisation: " + uor.getUserOrganisation() + .getOrganisation().getName()); return uo; } @@ -1164,16 +1136,14 @@ * at the same time as retrieving the tool data, rather than making a separate lookup. * * The return values are the entry for the select clause (will always have a leading space but no trailing comma and - * an - * alias of luser) and the sql join clause, which should go with any other join clauses. + * an alias of luser) and the sql join clause, which should go with any other join clauses. * - * To convert the portrait id set up the sql -> java object translation using - * addScalar("portraitId", IntegerType.INSTANCE) + * To convert the portrait id set up the sql -> java object translation using addScalar("portraitId", + * IntegerType.INSTANCE) * * @param userIdString - * User identifier field string e.g. user.user_id + * User identifier field string e.g. user.user_id * @return String[] { partial select string, join clause } - * */ @Override public String[] getPortraitSQL(String userIdString) { @@ -1331,8 +1301,8 @@ private ILogEventService getLogEventService() { if (UserManagementService.logEventService == null) { - WebApplicationContext ctx = WebApplicationContextUtils - .getWebApplicationContext(SessionManager.getServletContext()); + WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext( + SessionManager.getServletContext()); UserManagementService.logEventService = (ILogEventService) ctx.getBean("logEventService"); } return UserManagementService.logEventService; @@ -1341,4 +1311,4 @@ public void setCentralToolContentHandler(IToolContentHandler centralToolContentHandler) { this.centralToolContentHandler = centralToolContentHandler; } -} +} \ No newline at end of file Index: lams_tool_assessment/lams_tool_assessment.eml =================================================================== diff -u -re7b29886c3fc2a5edef72022a8df8b1833ac6b47 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_tool_assessment/lams_tool_assessment.eml (.../lams_tool_assessment.eml) (revision e7b29886c3fc2a5edef72022a8df8b1833ac6b47) +++ lams_tool_assessment/lams_tool_assessment.eml (.../lams_tool_assessment.eml) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -1,6 +1,10 @@ - + + + + + Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -r0586f1081f3b7e5b550da93b64463175ea698c28 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 0586f1081f3b7e5b550da93b64463175ea698c28) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -153,8 +153,9 @@ /** * @author Andrey Balan */ -public class AssessmentServiceImpl implements IAssessmentService, ICommonAssessmentService, ToolContentManager, - ToolSessionManager, ToolRestManager, IQbToolService { +public class AssessmentServiceImpl + implements IAssessmentService, ICommonAssessmentService, ToolContentManager, ToolSessionManager, + ToolRestManager, IQbToolService { private static Logger log = Logger.getLogger(AssessmentServiceImpl.class.getName()); private AssessmentDAO assessmentDao; @@ -204,9 +205,9 @@ public AssessmentServiceImpl() { FluxRegistry.initFluxMap(AssessmentConstants.COMPLETION_CHARTS_UPDATE_FLUX_NAME, - AssessmentConstants.ANSWERS_UPDATED_SINK_NAME, null, (Long toolContentId) -> UriUtils - .encode(getCompletionChartsData(toolContentId), StandardCharsets.UTF_8.toString()), - FluxMap.SHORT_THROTTLE, FluxMap.STANDARD_TIMEOUT); + AssessmentConstants.ANSWERS_UPDATED_SINK_NAME, null, + (Long toolContentId) -> UriUtils.encode(getCompletionChartsData(toolContentId), + StandardCharsets.UTF_8.toString()), FluxMap.SHORT_THROTTLE, FluxMap.STANDARD_TIMEOUT); } // ******************************************************************************* @@ -402,8 +403,8 @@ } /** - * How many learners have already finished answering questions. - * They are either on results page or left the activity completely. + * How many learners have already finished answering questions. They are either on results page or left the activity + * completely. */ @Override public int getCountLearnersWithFinishedCurrentAttempt(long contentId) { @@ -763,9 +764,10 @@ } } - boolean isAnswerModified = !Objects.equals(questionResult.getAnswerBoolean(), questionDto.getAnswerBoolean()) - || !Objects.equals(questionResult.getAnswerFloat(), questionDto.getAnswerFloat()) - || !Objects.equals(questionResult.getAnswer(), questionDto.getAnswer()); + boolean isAnswerModified = + !Objects.equals(questionResult.getAnswerBoolean(), questionDto.getAnswerBoolean()) || !Objects.equals( + questionResult.getAnswerFloat(), questionDto.getAnswerFloat()) || !Objects.equals( + questionResult.getAnswer(), questionDto.getAnswer()); // store question answer values questionResult.setAnswerBoolean(questionDto.getAnswerBoolean()); @@ -862,7 +864,6 @@ } /** - * * @return grade that user scored by answering that question */ private void calculateAnswerMark(Long assessmentUid, Long userId, AssessmentQuestionResult questionResult, @@ -932,9 +933,10 @@ boolean isAnswerMatchedCurrentOption = false; try { float answerFloat = Float.valueOf(questionDto.getAnswer()); - isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getNumericalOption() - - optionDto.getAcceptedError())) - && (answerFloat <= (optionDto.getNumericalOption() + optionDto.getAcceptedError()))); + isAnswerMatchedCurrentOption = ( + (answerFloat >= (optionDto.getNumericalOption() - optionDto.getAcceptedError())) && ( + answerFloat <= (optionDto.getNumericalOption() + + optionDto.getAcceptedError()))); } catch (Exception e) { } @@ -949,9 +951,8 @@ float answerFloat = Float.valueOf(answerFloatStr); answerFloat = answerFloat / unit.getMultiplier(); isAnswerMatchedCurrentOption = ((answerFloat >= (optionDto.getNumericalOption() - - optionDto.getAcceptedError())) - && (answerFloat <= (optionDto.getNumericalOption() - + optionDto.getAcceptedError()))); + - optionDto.getAcceptedError())) && (answerFloat <= ( + optionDto.getNumericalOption() + optionDto.getAcceptedError()))); if (isAnswerMatchedCurrentOption) { break; } @@ -970,8 +971,8 @@ } } else if (questionDto.getType() == QbQuestion.TYPE_TRUE_FALSE) { - if ((questionDto.getAnswerBoolean() == questionDto.getCorrectAnswer()) - && (questionDto.getAnswer() != null)) { + if ((questionDto.getAnswerBoolean() == questionDto.getCorrectAnswer()) && (questionDto.getAnswer() + != null)) { mark = maxMark; } @@ -1062,16 +1063,18 @@ Map questionToResultMap = lastResult.getQuestionResults().stream() .collect(Collectors.toMap(q -> q.getQbToolQuestion().getUid(), q -> q)); - Map questionToFinishedResultMap = lastFinishedResult == null ? null + Map questionToFinishedResultMap = lastFinishedResult == null + ? null : lastFinishedResult.getQuestionResults().stream() .collect(Collectors.toMap(q -> q.getQbToolQuestion().getUid(), q -> q)); for (Set questionsForOnePage : pagedQuestionDtos) { for (QuestionDTO questionDto : questionsForOnePage) { // load last finished results for hedging type of questions (in order to prevent retry) - AssessmentQuestionResult questionResult = (questionDto.getType() == QbQuestion.TYPE_MARK_HEDGING) - && (lastResult.getFinishDate() == null) && (lastFinishedResult != null) + AssessmentQuestionResult questionResult = + (questionDto.getType() == QbQuestion.TYPE_MARK_HEDGING) && (lastResult.getFinishDate() == null) + && (lastFinishedResult != null) ? questionToFinishedResultMap.get(questionDto.getUid()) : questionToResultMap.get(questionDto.getUid()); if (questionResult != null) { @@ -1263,7 +1266,8 @@ if (entry != null) { ReflectDTO ref = new ReflectDTO(user); ref.setReflect(entry.getEntry()); - Date postedDate = (entry.getLastModified() != null) ? entry.getLastModified() + Date postedDate = (entry.getLastModified() != null) + ? entry.getLastModified() : entry.getCreateDate(); ref.setDate(postedDate); reflectList.add(ref); @@ -1415,7 +1419,8 @@ AssessmentResult lastFinishedResult = assessmentResultDao.getLastFinishedAssessmentResultByUser(sessionId, userId); - long timeTaken = lastFinishedResult == null ? 0 + long timeTaken = lastFinishedResult == null + ? 0 : lastFinishedResult.getFinishDate().getTime() - lastFinishedResult.getStartDate().getTime(); userSummary.setTimeOfLastAttempt(new Date(timeTaken)); if (lastFinishedResult != null) { @@ -1491,8 +1496,8 @@ AssessmentQuestion question = assessmentQuestionDao.getByUid(questionUid); QbQuestion qbQuestion = question.getQbQuestion(); boolean isVSA = question.getType() == QbQuestion.TYPE_VERY_SHORT_ANSWERS; - List allQuestionResults = assessmentQuestionResultDao - .getQuestionResultsByQuestionUid(questionUid, !isVSA); + List allQuestionResults = assessmentQuestionResultDao.getQuestionResultsByQuestionUid( + questionUid, !isVSA); QuestionSummary questionSummary = new QuestionSummary(question); @@ -1526,8 +1531,8 @@ @Override public boolean recalculateMarksForVsaQuestion(Long toolQuestionUid, String answer) { // get all user results - List assessmentResults = assessmentResultDao - .getAssessmentResultsByQbToolQuestionAndAnswer(toolQuestionUid, answer); + List assessmentResults = assessmentResultDao.getAssessmentResultsByQbToolQuestionAndAnswer( + toolQuestionUid, answer); QbToolQuestion toolQuestion = assessmentResultDao.find(QbToolQuestion.class, toolQuestionUid); Long qbQuestionUid = toolQuestion.getQbQuestion().getUid(); //stores userId->lastFinishedAssessmentResult @@ -1545,8 +1550,8 @@ for (AssessmentQuestionResult questionResult : assessmentResult.getQuestionResults()) { if (questionResult.getQbQuestion().getUid().equals(qbQuestionUid)) { Float oldQuestionAnswerMark = questionResult.getMark(); - int oldResultMaxMark = questionResult.getMaxMark() == null ? 0 - : questionResult.getMaxMark().intValue(); + int oldResultMaxMark = + questionResult.getMaxMark() == null ? 0 : questionResult.getMaxMark().intValue(); //actually recalculate marks QuestionDTO questionDto = new QuestionDTO(questionResult.getQbToolQuestion()); @@ -1830,8 +1835,8 @@ boolean allowAnswerJustification = assessment.isAllowAnswerJustification(); if (!allowAnswerJustification) { for (AssessmentQuestion question : questions) { - if (question.getType().equals(QbQuestion.TYPE_MARK_HEDGING) - && question.getQbQuestion().isHedgingJustificationEnabled()) { + if (question.getType().equals(QbQuestion.TYPE_MARK_HEDGING) && question.getQbQuestion() + .isHedgingJustificationEnabled()) { allowAnswerJustification = true; break; } @@ -1921,8 +1926,7 @@ } QuestionSummary questionSummary = questionSummaries.get(question.getUid()); - List> allResultsForQuestion = questionSummary - .getQuestionResultsPerSession(); + List> allResultsForQuestion = questionSummary.getQuestionResultsPerSession(); int markCount = 0; float markTotal = 0.0F; @@ -1932,11 +1936,12 @@ for (AssessmentQuestionResult questionResult : resultList) { ExcelRow userResultRow = new ExcelRow(); userResultRow.addCell(questionResult.getQbQuestion().getName()); - userResultRow.addCell(AssessmentServiceImpl - .getQuestionTypeLanguageLabel(questionResult.getQbQuestion().getType())); + userResultRow.addCell(AssessmentServiceImpl.getQuestionTypeLanguageLabel( + questionResult.getQbQuestion().getType())); userResultRow.addCell(Float.valueOf(questionResult.getQbQuestion().getPenaltyFactor())); - Float maxMark = (questionResult.getMaxMark() == null) ? 0 + Float maxMark = (questionResult.getMaxMark() == null) + ? 0 : Float.valueOf(questionResult.getMaxMark()); userResultRow.addCell(maxMark); userResultRow.addCell(questionResult.getUser().getLoginName()); @@ -1961,8 +1966,8 @@ } } else { - AssessmentExcelCell assessmentCell = AssessmentEscapeUtils - .addResponseCellForExcelExport(questionResult, false); + AssessmentExcelCell assessmentCell = AssessmentEscapeUtils.addResponseCellForExcelExport( + questionResult, false); userResultRow.addCell(assessmentCell.value, assessmentCell.isHighlighted ? IndexedColors.GREEN : IndexedColors.AUTOMATIC); @@ -1991,9 +1996,8 @@ //mark //calculating markCount & markTotal if (questionResult.getMark() != null && questionResult.getFinishDate() != null) { - userResultRow.addCell(questionResult.getMarkedBy() == null - && question.getType().equals(QbQuestion.TYPE_ESSAY) ? "-" - : questionResult.getMark().toString()); + userResultRow.addCell(questionResult.getMarkedBy() == null && question.getType() + .equals(QbQuestion.TYPE_ESSAY) ? "-" : questionResult.getMark().toString()); markCount++; markTotal += questionResult.getMark(); @@ -2002,8 +2006,8 @@ } if (allowAnswerJustification) { - userResultRow.addCell(AssessmentEscapeUtils - .escapeStringForExcelExport(questionResult.getJustification())); + userResultRow.addCell(AssessmentEscapeUtils.escapeStringForExcelExport( + questionResult.getJustification())); } userResultRow.addCell( questionResult.getMarkedBy() == null ? "" : questionResult.getMarkedBy().getFullName()); @@ -2015,8 +2019,8 @@ } if (doSummaryTable) { - questionSummarySheet - .addRow(outputSummaryTable(question, summaryOfAnswers, summaryNACount, trueKey, falseKey)); + questionSummarySheet.addRow( + outputSummaryTable(question, summaryOfAnswers, summaryNACount, trueKey, falseKey)); questionSummarySheet.addEmptyRow(); } questionSummarySheet.getRows().addAll(questionSummaryTabTemp); @@ -2129,8 +2133,8 @@ userSummaryUserHeadersRow.addCell(getMessage("label.monitoring.summary.total"), ExcelCell.BORDER_STYLE_LEFT_THIN); - List assessmentResults = assessmentResultDao - .getLastFinishedAssessmentResults(assessment.getContentId()); + List assessmentResults = assessmentResultDao.getLastFinishedAssessmentResults( + assessment.getContentId()); Map userUidToResultMap = assessmentResults.stream() .collect(Collectors.toMap(r -> r.getUser().getUid(), r -> r)); @@ -2154,31 +2158,32 @@ if (questionResults == null || questionResults.isEmpty()) { continue; } - Map questionResultsMap = questionResults.stream().collect(Collectors - .toMap(questionResult -> questionResult.getQbToolQuestion().getUid(), Function.identity())); + Map questionResultsMap = questionResults.stream().collect( + Collectors.toMap(questionResult -> questionResult.getQbToolQuestion().getUid(), + Function.identity())); // get information when a learner started interaction with given questions - Map learnerInteractions = learnerInteractionService - .getFirstLearnerInteractions(assessment.getContentId(), - assessmentUser.getUserId().intValue()); + Map learnerInteractions = learnerInteractionService.getFirstLearnerInteractions( + assessment.getContentId(), assessmentUser.getUserId().intValue()); // follow question reference ordering, to QbToolQuestion's for (QuestionReference questionReference : questionReferences) { - AssessmentQuestionResult questionResult = questionResultsMap - .get(questionReference.getQuestion().getUid()); + AssessmentQuestionResult questionResult = questionResultsMap.get( + questionReference.getQuestion().getUid()); // mark userResultRow.addCell(questionResult.getMark(), ExcelCell.BORDER_STYLE_LEFT_THIN); // option chosen or full answer - AssessmentExcelCell assessmentCell = AssessmentEscapeUtils - .addResponseCellForExcelExport(questionResult, true); + AssessmentExcelCell assessmentCell = AssessmentEscapeUtils.addResponseCellForExcelExport( + questionResult, true); userResultRow.addCell(assessmentCell.value, assessmentCell.isHighlighted ? IndexedColors.GREEN : IndexedColors.AUTOMATIC); // learner interaction QbQuestion question = questionResult.getQbQuestion(); if (QbQuestion.TYPE_ESSAY == question.getType()) { - userResultRow.addCell(questionResult.getMarkedBy() == null ? "" + userResultRow.addCell(questionResult.getMarkedBy() == null + ? "" : questionResult.getMarkedBy().getFullName()); userResultRow.addCell(questionResult.getMarkerComment()); } @@ -2187,7 +2192,8 @@ || QbQuestion.TYPE_TRUE_FALSE == question.getType(); if (addAnsweredDateColumn) { // only put interaction time into sheet if auto submit picked up answer - LearnerInteractionEvent interaction = assessmentCell.value == null ? null + LearnerInteractionEvent interaction = assessmentCell.value == null + ? null : learnerInteractions.get(questionResult.getQbToolQuestion().getUid()); if (interaction == null) { userResultRow.addEmptyCell(); @@ -2204,14 +2210,13 @@ switch (assessment.getConfidenceLevelsType()) { case 2: confidenceLevel = new String[] { getMessage("label.not.confident"), - getMessage("label.confident"), - getMessage("label.very.confident") }[questionResult.getConfidenceLevel() - / 5]; + getMessage("label.confident"), getMessage("label.very.confident") }[ + questionResult.getConfidenceLevel() / 5]; break; case 3: confidenceLevel = new String[] { getMessage("label.not.sure"), - getMessage("label.sure"), - getMessage("label.very.sure") }[questionResult.getConfidenceLevel() / 5]; + getMessage("label.sure"), getMessage("label.very.sure") }[ + questionResult.getConfidenceLevel() / 5]; break; default: confidenceLevel = questionResult.getConfidenceLevel() * 10 + "%"; @@ -2297,8 +2302,8 @@ } } else if (question.getType() == QbQuestion.TYPE_VERY_SHORT_ANSWERS || question.getType() == QbQuestion.TYPE_NUMERICAL) { - Long submittedOptionUid = questionResult.getQbOption() == null ? null - : questionResult.getQbOption().getUid(); + Long submittedOptionUid = + questionResult.getQbOption() == null ? null : questionResult.getQbOption().getUid(); if (submittedOptionUid != null) { Integer currentCount = summaryOfAnswers.get(submittedOptionUid); if (currentCount == null) { @@ -2335,7 +2340,8 @@ || question.getType() == QbQuestion.TYPE_VERY_SHORT_ANSWERS || question.getType() == QbQuestion.TYPE_NUMERICAL) { for (QbOption option : question.getQbQuestion().getQbOptions()) { - Double optionPercentage = total == 0 || summaryOfAnswers.get(option.getUid()) == null ? 0 + Double optionPercentage = total == 0 || summaryOfAnswers.get(option.getUid()) == null + ? 0 : (double) summaryOfAnswers.get(option.getUid()) / total; ExcelCell optionCell = summaryTableRow.addPercentageCell(optionPercentage); if (option.getMaxMark() > 0) { @@ -2344,11 +2350,13 @@ } } else { - Double correctPercentage = total == 0 || summaryOfAnswers.get(trueKey) == null ? 0 + Double correctPercentage = total == 0 || summaryOfAnswers.get(trueKey) == null + ? 0 : (double) summaryOfAnswers.get(trueKey) / total; ExcelCell correctCell = summaryTableRow.addPercentageCell(correctPercentage); - Double wrongPercentage = total == 0 || summaryOfAnswers.get(falseKey) == null ? 0 + Double wrongPercentage = total == 0 || summaryOfAnswers.get(falseKey) == null + ? 0 : (double) summaryOfAnswers.get(falseKey) / total; ExcelCell wrongCell = summaryTableRow.addPercentageCell(wrongPercentage); @@ -2398,8 +2406,8 @@ // nothing to chagne return; } - AssessmentQuestionResult questionResult = assessmentQuestionResultDao - .getAssessmentQuestionResultByUid(questionResultUid); + AssessmentQuestionResult questionResult = assessmentQuestionResultDao.getAssessmentQuestionResultByUid( + questionResultUid); if (newMark != null) { float oldMark = questionResult.getMark(); AssessmentResult assessmentResult = questionResult.getAssessmentResult(); @@ -2428,8 +2436,8 @@ for (AssessmentUser user : users) { Long userId = user.getUserId(); - List questionResults = assessmentQuestionResultDao - .getAssessmentQuestionResultList(assessment.getUid(), userId, questionUid); + List questionResults = assessmentQuestionResultDao.getAssessmentQuestionResultList( + assessment.getUid(), userId, questionUid); if ((questionResults == null) || questionResults.isEmpty()) { log.warn("User with uid: " + user.getUid() @@ -2506,16 +2514,20 @@ if (((oldQuestion.getType() == QbQuestion.TYPE_VERY_SHORT_ANSWERS) && !StringUtils.equals(oldOption.getName(), newOption.getName())) //numbering - || (oldOption.getNumericalOption() != newOption.getNumericalOption()) - || (oldOption.getAcceptedError() != newOption.getAcceptedError()) + || (oldOption.getNumericalOption() != newOption.getNumericalOption()) || ( + oldOption.getAcceptedError() != newOption.getAcceptedError()) //option grade || (oldOption.getMaxMark() != newOption.getMaxMark()) //changed correct option || (oldOption.isCorrect() != newOption.isCorrect())) { isQuestionModified = true; + break; } } } + if (isQuestionModified) { + break; + } } if (oldOptions.size() != newOptions.size()) { isQuestionModified = true; @@ -2533,8 +2545,8 @@ Map modifiedReferences = new HashMap<>(); for (QuestionReference oldReference : oldReferences) { for (QuestionReference newReference : newReferences) { - if (oldReference.getUid().equals(newReference.getUid()) - && (oldReference.getMaxMark() != newReference.getMaxMark())) { + if (oldReference.getUid().equals(newReference.getUid()) && (oldReference.getMaxMark() + != newReference.getMaxMark())) { modifiedReferences.put(newReference, oldReference.getMaxMark()); } } @@ -2550,7 +2562,8 @@ // get all finished user results List assessmentResults = assessmentResultDao.getAssessmentResults(assessmentUid, user.getUserId()); - AssessmentResult lastFinishedAssessmentResult = (assessmentResults.isEmpty()) ? null + AssessmentResult lastFinishedAssessmentResult = (assessmentResults.isEmpty()) + ? null : assessmentResults.get(assessmentResults.size() - 1); //add autosave assessmentResult as well @@ -2569,8 +2582,8 @@ for (AssessmentQuestionResult questionResult : questionResults) { QbToolQuestion oldQuestion = questionResult.getQbToolQuestion(); Float oldQuestionAnswerMark = questionResult.getMark(); - int oldResultMaxMark = questionResult.getMaxMark() == null ? 0 - : questionResult.getMaxMark().intValue(); + int oldResultMaxMark = + questionResult.getMaxMark() == null ? 0 : questionResult.getMaxMark().intValue(); //check whether according question was modified for (AssessmentQuestion modifiedQuestion : modifiedQuestions) { @@ -2590,20 +2603,24 @@ //find according old qbOption QbOption oldOption = null; + int oldOptionDisplayOrder = 1; for (QbOption oldOptionIter : oldQuestion.getQbQuestion().getQbOptions()) { if (oldOptionIter.getUid().equals(oldOptionAnswer.getOptionUid())) { oldOption = oldOptionIter; break; } + oldOptionDisplayOrder++; } if (oldOption != null) { //update + int newOptionDisplayOrder = 1; for (QbOption newOption : modifiedQuestion.getQbQuestion().getQbOptions()) { - if (oldOption.getDisplayOrder() == newOption.getDisplayOrder()) { + if (oldOptionDisplayOrder == newOptionDisplayOrder) { oldOptionAnswer.setOptionUid(newOption.getUid()); break; } + newOptionDisplayOrder++; } } } @@ -2628,15 +2645,15 @@ Long questionUid = questionResult.getQbToolQuestion().getUid(); for (QuestionReference modifiedReference : modifiedReferences.keySet()) { - if (!modifiedReference.isRandomQuestion() - && questionUid.equals(modifiedReference.getQuestion().getUid())) { + if (!modifiedReference.isRandomQuestion() && questionUid.equals( + modifiedReference.getQuestion().getUid())) { int newReferenceMaxMark = modifiedReference.getMaxMark(); int oldReferenceMaxMark = modifiedReferences.get(modifiedReference); // update question answer's mark Float oldQuestionAnswerMark = questionResult.getMark(); - float newQuestionAnswerMark = (oldQuestionAnswerMark * newReferenceMaxMark) - / oldReferenceMaxMark; + float newQuestionAnswerMark = + (oldQuestionAnswerMark * newReferenceMaxMark) / oldReferenceMaxMark; questionResult.setMark(newQuestionAnswerMark); questionResult.setMaxMark((float) newReferenceMaxMark); assessmentQuestionResultDao.saveObject(questionResult); @@ -2658,8 +2675,8 @@ } } } - Collection randomQuestionResults = CollectionUtils - .subtract(questionResults, nonRandomQuestionResults); + Collection randomQuestionResults = CollectionUtils.subtract( + questionResults, nonRandomQuestionResults); // [+] if the question reference mark is modified (in case of random question references) for (QuestionReference modifiedReference : modifiedReferences.keySet()) { @@ -2676,8 +2693,8 @@ // update question answer's mark Float oldQuestionResultMark = randomQuestionResult.getMark(); - float newQuestionResultMark = (oldQuestionResultMark * newReferenceMaxMark) - / oldReferenceMaxMark; + float newQuestionResultMark = + (oldQuestionResultMark * newReferenceMaxMark) / oldReferenceMaxMark; randomQuestionResult.setMark(newQuestionResultMark); randomQuestionResult.setMaxMark((float) newReferenceMaxMark); assessmentQuestionResultDao.saveObject(randomQuestionResult); @@ -2708,8 +2725,8 @@ AssessmentResult lastFinishedAssessmentResult, float newAssessmentMark, int newAssessmentMaxMark, AssessmentUser user) { // store new mark and maxMark if they were changed - if ((assessmentResult.getGrade() != newAssessmentMark) - || (assessmentResult.getMaximumGrade() != newAssessmentMaxMark)) { + if ((assessmentResult.getGrade() != newAssessmentMark) || (assessmentResult.getMaximumGrade() + != newAssessmentMaxMark)) { // marks can't be below zero newAssessmentMark = (newAssessmentMark < 0) ? 0 : newAssessmentMark; @@ -2720,8 +2737,8 @@ assessmentResultDao.saveObject(assessmentResult); // if this is the last finished assessment result - propagade total mark to Gradebook - if (lastFinishedAssessmentResult != null - && lastFinishedAssessmentResult.getUid().equals(assessmentResult.getUid())) { + if (lastFinishedAssessmentResult != null && lastFinishedAssessmentResult.getUid() + .equals(assessmentResult.getUid())) { toolService.updateActivityMark(Double.valueOf(newAssessmentMark), null, user.getUserId().intValue(), user.getSession().getSessionId(), false); } @@ -3305,8 +3322,9 @@ } else { log.error("Fail to leave tool Session.Could not find shared assessment " + "session by given session id: " + toolSessionId); - throw new DataMissingException("Fail to leave tool Session." - + "Could not find shared assessment session by given session id: " + toolSessionId); + throw new DataMissingException( + "Fail to leave tool Session." + "Could not find shared assessment session by given session id: " + + toolSessionId); } return toolService.completeToolSession(toolSessionId, learnerId); } @@ -3369,17 +3387,18 @@ for (QbOption option : qbQuestion.getQbOptions()) { for (AssessmentOptionAnswer optionAnswer : questionResult.getOptionAnswers()) { - if (optionAnswer.getAnswerBoolean() - && (optionAnswer.getOptionUid().equals(option.getUid()))) { + if (optionAnswer.getAnswerBoolean() && (optionAnswer.getOptionUid() + .equals(option.getUid()))) { ConfidenceLevelDTO confidenceLevelDto = new ConfidenceLevelDTO(); confidenceLevelDto.setUserId(user.getUserId().intValue()); - String userName = StringUtils.isBlank(user.getFirstName()) - && StringUtils.isBlank(user.getLastName()) ? user.getLoginName() - : user.getFirstName() + " " + user.getLastName(); + String userName = StringUtils.isBlank(user.getFirstName()) && StringUtils.isBlank( + user.getLastName()) + ? user.getLoginName() + : user.getFirstName() + " " + user.getLastName(); confidenceLevelDto.setUserName(userName); - confidenceLevelDto - .setPortraitUuid(portraitUuid == null ? null : portraitUuid.toString()); + confidenceLevelDto.setPortraitUuid( + portraitUuid == null ? null : portraitUuid.toString()); confidenceLevelDto.setQbQuestionUid(qbQuestion.getUid()); confidenceLevelDto.setLevel(questionResult.getConfidenceLevel()); @@ -3396,8 +3415,9 @@ ConfidenceLevelDTO confidenceLevelDto = new ConfidenceLevelDTO(); confidenceLevelDto.setUserId(user.getUserId().intValue()); - String userName = StringUtils.isBlank(user.getFirstName()) - && StringUtils.isBlank(user.getLastName()) ? user.getLoginName() + String userName = + StringUtils.isBlank(user.getFirstName()) && StringUtils.isBlank(user.getLastName()) + ? user.getLoginName() : user.getFirstName() + " " + user.getLastName(); confidenceLevelDto.setUserName(userName); confidenceLevelDto.setPortraitUuid(portraitUuid == null ? null : portraitUuid.toString()); @@ -3466,8 +3486,8 @@ //find and store optionUid for (QbOption option : qbQuestion.getQbOptions()) { for (AssessmentOptionAnswer optionAnswer : questionResult.getOptionAnswers()) { - if (optionAnswer.getAnswerBoolean() - && (optionAnswer.getOptionUid().equals(option.getUid()))) { + if (optionAnswer.getAnswerBoolean() && (optionAnswer.getOptionUid() + .equals(option.getUid()))) { Long optionUid = option.getUid(); vsaAnswerDTO.setQbOptionUid(optionUid); break; @@ -3478,8 +3498,9 @@ ConfidenceLevelDTO confidenceLevelDto = new ConfidenceLevelDTO(); confidenceLevelDto.setUserId(user.getUserId().intValue()); - String userName = StringUtils.isBlank(user.getFirstName()) - && StringUtils.isBlank(user.getLastName()) ? user.getLoginName() + String userName = + StringUtils.isBlank(user.getFirstName()) && StringUtils.isBlank(user.getLastName()) + ? user.getLoginName() : user.getFirstName() + " " + user.getLastName(); confidenceLevelDto.setUserName(userName); confidenceLevelDto.setPortraitUuid(portraitUuid == null ? null : portraitUuid.toString()); @@ -3496,8 +3517,8 @@ } /** - * Counts how many questions were answered correctly by the given user, regardless of the mark given. - * Currently it only works for MCQ and mark hedging questions. + * Counts how many questions were answered correctly by the given user, regardless of the mark given. Currently it + * only works for MCQ and mark hedging questions. */ @Override public Integer countCorrectAnswers(long toolContentId, int userId) { @@ -3729,8 +3750,8 @@ * "answerFloat", "displayOrder" (Integer), "grade" (Integer). * * The references entry should be a ArrayNode containing JSON objects, which in turn must contain "displayOrder" - * (Integer), "questionDisplayOrder" (Integer - to match to the question). It may also have "maxMark" (Integer) - * and "randomQuestion" (Boolean) + * (Integer), "questionDisplayOrder" (Integer - to match to the question). It may also have "maxMark" (Integer) and + * "randomQuestion" (Boolean) * * @throws IOException */ @@ -3750,12 +3771,12 @@ assessment.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); assessment.setAllowGradesAfterAttempt( JsonUtil.optBoolean(toolContentJSON, "allowGradesAfterAttempt", Boolean.FALSE)); - assessment - .setAllowHistoryResponses(JsonUtil.optBoolean(toolContentJSON, "allowHistoryResponses", Boolean.FALSE)); + assessment.setAllowHistoryResponses( + JsonUtil.optBoolean(toolContentJSON, "allowHistoryResponses", Boolean.FALSE)); assessment.setAllowOverallFeedbackAfterQuestion( JsonUtil.optBoolean(toolContentJSON, "allowOverallFeedbackAfterQuestion", Boolean.FALSE)); - assessment - .setAllowQuestionFeedback(JsonUtil.optBoolean(toolContentJSON, "allowQuestionFeedback", Boolean.FALSE)); + assessment.setAllowQuestionFeedback( + JsonUtil.optBoolean(toolContentJSON, "allowQuestionFeedback", Boolean.FALSE)); assessment.setAllowDiscloseAnswers(JsonUtil.optBoolean(toolContentJSON, "allowDiscloseAnswers", Boolean.FALSE)); assessment.setAllowRightAnswersAfterQuestion( JsonUtil.optBoolean(toolContentJSON, "allowRightAnswersAfterQuestion", Boolean.FALSE)); @@ -3880,12 +3901,13 @@ assessmentDao.insert(qbQuestion); } - if ((type == QbQuestion.TYPE_MATCHING_PAIRS) || (type == QbQuestion.TYPE_MULTIPLE_CHOICE) - || (type == QbQuestion.TYPE_NUMERICAL) || (type == QbQuestion.TYPE_MARK_HEDGING)) { + if ((type == QbQuestion.TYPE_MATCHING_PAIRS) || (type == QbQuestion.TYPE_MULTIPLE_CHOICE) || (type + == QbQuestion.TYPE_NUMERICAL) || (type == QbQuestion.TYPE_MARK_HEDGING)) { if (!questionJSONData.has(RestTags.ANSWERS)) { - throw new IOException("REST Authoring is missing answers for a question of type " + type - + ". Data:" + toolContentJSON); + throw new IOException( + "REST Authoring is missing answers for a question of type " + type + ". Data:" + + toolContentJSON); } List optionList = new ArrayList<>(); @@ -3923,7 +3945,7 @@ qbQuestion.setQbOptions(optionList); } - Long collectionUid = JsonUtil.optLong(questionJSONData, RestTags.COLLECTION_UID); + Long collectionUid = JsonUtil.optLong(toolContentJSON, RestTags.COLLECTION_UID); if (collectionUid == null) { // if no collection UUID was specified, questions end up in user's private collection if (privateCollectionUUID == null) { @@ -3932,24 +3954,23 @@ collectionUid = privateCollectionUUID; } - boolean addToCollection = true; + boolean addToCollection = !isModification; // check if it is the same collection - there is a good chance it is - if (collection == null || collectionUid != collection.getUid()) { + if (addToCollection && (collection == null || collectionUid != collection.getUid())) { collection = qbService.getCollection(collectionUid); if (collection == null) { addToCollection = false; } else { collectionUUIDs = qbService.getCollectionQuestions(collection.getUid()).stream() .peek(q -> qbService.releaseFromCache(q)).filter(q -> q.getUuid() != null) .collect(Collectors.mapping(q -> q.getUuid().toString(), Collectors.toSet())); + if (collectionUUIDs.contains(uuid)) { + addToCollection = false; + } } } if (isModification) { - if (collectionUUIDs != null) { - addToCollection &= !collectionUUIDs.contains(uuid); - } - int isModified = qbQuestion.isQbQuestionModified(oldQbQuestion); if (isModified == IQbService.QUESTION_MODIFIED_VERSION_BUMP) { qbQuestion.clearID(); @@ -4020,8 +4041,8 @@ AssessmentQuestion matchingQuestion = matchQuestion(newQuestionSet, JsonUtil.optInt(referenceJSONData, "questionDisplayOrder")); if (matchingQuestion == null) { - throw new IOException("Unable to find matching question for displayOrder " - + referenceJSONData.get("questionDisplayOrder") + ". Data:" + toolContentJSON); + throw new IOException("Unable to find matching question for displayOrder " + referenceJSONData.get( + "questionDisplayOrder") + ". Data:" + toolContentJSON); } reference.setQuestion(matchingQuestion); // either take the parameter or get default question grade @@ -4051,8 +4072,8 @@ // TODO Implement REST support for all types and then remove checkType method void checkType(Integer type) throws IOException { - if ((type != QbQuestion.TYPE_ESSAY) && (type != QbQuestion.TYPE_MULTIPLE_CHOICE) - && (type != QbQuestion.TYPE_MARK_HEDGING)) { + if ((type != QbQuestion.TYPE_ESSAY) && (type != QbQuestion.TYPE_MULTIPLE_CHOICE) && (type + != QbQuestion.TYPE_MARK_HEDGING)) { throw new IOException( "Assessment Tool does not support REST Authoring for anything but Essay, Multiple Choice and Mark Hedging types. Found type " + type); @@ -4096,8 +4117,8 @@ @Override public Grouping getGrouping(long toolContentId) { - ToolActivity toolActivity = (ToolActivity) userManagementService - .findByProperty(ToolActivity.class, "toolContentId", toolContentId).get(0); + ToolActivity toolActivity = (ToolActivity) userManagementService.findByProperty(ToolActivity.class, + "toolContentId", toolContentId).get(0); return toolActivity.getApplyGrouping() ? toolActivity.getGrouping() : null; } @@ -4130,8 +4151,9 @@ public void changeLeaderForGroup(long toolSessionId, long leaderUserId) { AssessmentSession session = getSessionBySessionId(toolSessionId); if (AssessmentConstants.COMPLETED == session.getStatus()) { - throw new InvalidParameterException("Attempting to assing a new leader with user ID " + leaderUserId - + " to a finished session wtih ID " + toolSessionId); + throw new InvalidParameterException( + "Attempting to assing a new leader with user ID " + leaderUserId + " to a finished session wtih ID " + + toolSessionId); } AssessmentUser existingLeader = session.getGroupLeader(); @@ -4150,8 +4172,9 @@ + toolSessionId); } } else if (!newLeader.getSession().getSessionId().equals(toolSessionId)) { - throw new InvalidParameterException("User with ID " + leaderUserId + " belongs to session with ID " - + newLeader.getSession().getSessionId() + " and not to session with ID " + toolSessionId); + throw new InvalidParameterException( + "User with ID " + leaderUserId + " belongs to session with ID " + newLeader.getSession() + .getSessionId() + " and not to session with ID " + toolSessionId); } else { AssessmentResult newLeaderResult = getLastAssessmentResult(assessment.getUid(), leaderUserId); if (newLeaderResult != null) { @@ -4163,9 +4186,10 @@ existingLeader.getUserId()); if (existingLeaderResult != null) { if (existingLeaderResult.getFinishDate() != null) { - throw new InvalidParameterException("Attempting to assing a finished result of leader with user ID " - + existingLeader.getUserId() + " to a new leader with user ID " + leaderUserId - + " in session wtih ID " + toolSessionId); + throw new InvalidParameterException( + "Attempting to assing a finished result of leader with user ID " + existingLeader.getUserId() + + " to a new leader with user ID " + leaderUserId + " in session wtih ID " + + toolSessionId); } existingLeaderResult.setUser(newLeader); Index: lams_tool_scratchie/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r8a7a259deba12163c46440a712e41bde926fdaf8 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_tool_scratchie/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 8a7a259deba12163c46440a712e41bde926fdaf8) +++ lams_tool_scratchie/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -301,3 +301,5 @@ label.prevent.learner.autosave.mutliple.tabs = You seem to have two LAMS tabs open for this exam. Please close one of them. Otherwise, answers will not be recorder properly and affect your score. label.exact.match = Learner answer must exactly match expected answer label.burning.questions.none = No burning questions yet... +label.questions.choice.collection.new.option = +label.questions.choice.collection.new.prompt = Enter a name for the new collection: \ No newline at end of file Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java =================================================================== diff -u -rb51fd1534812233131727a497422305bfad3d6c8 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision b51fd1534812233131727a497422305bfad3d6c8) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/service/ScratchieServiceImpl.java (.../ScratchieServiceImpl.java) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -130,8 +130,9 @@ /** * @author Andrey Balan */ -public class ScratchieServiceImpl implements IScratchieService, ICommonScratchieService, ToolContentManager, - ToolSessionManager, ToolRestManager, IQbToolService { +public class ScratchieServiceImpl + implements IScratchieService, ICommonScratchieService, ToolContentManager, ToolSessionManager, ToolRestManager, + IQbToolService { private static Logger log = Logger.getLogger(ScratchieServiceImpl.class.getName()); private ScratchieDAO scratchieDao; @@ -234,7 +235,8 @@ @Override public ScratchieUser getUserByLoginAndSessionId(String login, long toolSessionId) { List user = scratchieUserDao.findByProperty(User.class, "login", login); - return user.isEmpty() ? null + return user.isEmpty() + ? null : scratchieUserDao.getUserByUserIDAndSessionID(user.get(0).getUserId().longValue(), toolSessionId); } @@ -301,8 +303,8 @@ @Override public void populateItemsWithConfidenceLevels(Long userId, Long toolSessionId, Integer confidenceLevelsActivityUiid, Collection items) { - List confidenceLevelDtos = toolService - .getConfidenceLevelsByActivity(confidenceLevelsActivityUiid, userId.intValue(), toolSessionId); + List confidenceLevelDtos = toolService.getConfidenceLevelsByActivity( + confidenceLevelsActivityUiid, userId.intValue(), toolSessionId); //populate Scratchie items with confidence levels for (ScratchieItem item : items) { @@ -576,7 +578,8 @@ Long toolSessionId = session.getSessionId(); List visitLogsToDelete = new ArrayList<>(); String newPresetMarks = scratchie.getPresetMarks(); - boolean isRecalculateMarks = oldPresetMarks == null ? newPresetMarks != null + boolean isRecalculateMarks = oldPresetMarks == null + ? newPresetMarks != null : newPresetMarks == null || !oldPresetMarks.equals(newPresetMarks); // remove all scratches for modified items @@ -826,8 +829,7 @@ /* * If isIncludeOnlyLeaders then include the portrait ids needed for monitoring. If false then it * is probably the export and that doesn't need portraits. - */ - public List getMonitoringSummary(Long contentId) { + */ public List getMonitoringSummary(Long contentId) { List groupSummaryList = new ArrayList<>(); List sessions = scratchieSessionDao.getByContentId(contentId); @@ -903,8 +905,8 @@ // -1 if there is no log int attemptNumber = -1; for (ScratchieAnswerVisitLog itemLog : itemLogs) { - if (itemLog.getQbToolQuestion().getUid().equals(item.getUid()) - && isAnswersEqual(item, itemLog.getAnswer(), optionDto.getAnswer())) { + if (itemLog.getQbToolQuestion().getUid().equals(item.getUid()) && isAnswersEqual(item, + itemLog.getAnswer(), optionDto.getAnswer())) { // adding 1 to start from 1 attemptNumber = itemLogs.indexOf(itemLog) + 1; break; @@ -944,8 +946,8 @@ if (QbQuestion.TYPE_MULTIPLE_CHOICE == item.getQbQuestion().getType() || QbQuestion.TYPE_MARK_HEDGING == item.getQbQuestion().getType()) { for (ScratchieAnswerVisitLog userLog : userLogs) { - if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) - && userLog.getQbOption().getUid().equals(optionDto.getQbOptionUid())) { + if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) && userLog.getQbOption().getUid() + .equals(optionDto.getQbOptionUid())) { isScratched = true; break; } @@ -955,8 +957,8 @@ } else { // find according log if it exists for (ScratchieAnswerVisitLog userLog : userLogs) { - if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) - && isAnswersEqual(item, userLog.getAnswer(), optionDto.getAnswer())) { + if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) && isAnswersEqual(item, + userLog.getAnswer(), optionDto.getAnswer())) { isScratched = true; break; } @@ -980,7 +982,7 @@ ScratchieUser leader = scratchieSessionDao.getSessionBySessionId(toolSessionId).getGroupLeader(); Collection assessmentAnswers = scratchie.isAnswersFetchingEnabled() ? toolService.getVsaAnswersFromAssessment(scratchie.getActivityUiidProvidingVsaAnswers(), - leader.getUserId().intValue(), toolSessionId) + leader.getUserId().intValue(), toolSessionId) : null; for (ScratchieItem item : items) { @@ -1033,8 +1035,8 @@ OptionDTO optionDto = null; boolean skipAddingUserAnswerToConfidenceLevel = false; for (OptionDTO optionDtoIter : item.getOptionDtos()) { - if (itemQbQuestionUid.equals(optionDtoIter.getQbQuestionUid()) - && isAnswersEqual(item, optionDtoIter.getAnswer(), userLog.getAnswer())) { + if (itemQbQuestionUid.equals(optionDtoIter.getQbQuestionUid()) && isAnswersEqual(item, + optionDtoIter.getAnswer(), userLog.getAnswer())) { optionDto = optionDtoIter; //skip showing ConfidenceLevel, as we already show it due to this user's answer in Assessment skipAddingUserAnswerToConfidenceLevel = optionDtoIter.getUserId() @@ -1060,8 +1062,9 @@ ConfidenceLevelDTO confidenceLevelDto = new ConfidenceLevelDTO(); confidenceLevelDto.setUserId(leader.getUserId().intValue()); - String userName = StringUtils.isBlank(leader.getFirstName()) - && StringUtils.isBlank(leader.getLastName()) ? leader.getLoginName() + String userName = + StringUtils.isBlank(leader.getFirstName()) && StringUtils.isBlank(leader.getLastName()) + ? leader.getLoginName() : leader.getFirstName() + " " + leader.getLastName(); confidenceLevelDto.setUserName(userName); confidenceLevelDto.setPortraitUuid(leader.getPortraitId()); @@ -1077,9 +1080,9 @@ * Check if the specified item was unraveled by user * * @param item - * specified item + * specified item * @param userLogs - * uses logs from it (The main reason to have this parameter is to reduce number of queries to DB) + * uses logs from it (The main reason to have this parameter is to reduce number of queries to DB) * @return */ private boolean isItemUnraveled(ScratchieItem item, List userLogs) { @@ -1091,8 +1094,8 @@ ScratchieAnswerVisitLog log = null; for (ScratchieAnswerVisitLog userLog : userLogs) { - if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) - && userLog.getQbOption().getUid().equals(option.getUid())) { + if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) && userLog.getQbOption().getUid() + .equals(option.getUid())) { log = userLog; break; } @@ -1106,8 +1109,8 @@ //VSA question } else { for (ScratchieAnswerVisitLog userLog : userLogs) { - if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) - && StringUtils.isNotBlank(userLog.getAnswer())) { + if (userLog.getQbToolQuestion().getUid().equals(item.getUid()) && StringUtils.isNotBlank( + userLog.getAnswer())) { isItemUnraveled = isItemUnraveled(item, userLog); if (isItemUnraveled) { break; @@ -1145,7 +1148,8 @@ break; } // if the option has the highest grade, it is considered the correct one - if (correctAnswersGroup == null ? option.getMaxMark() > 0 + if (correctAnswersGroup == null + ? option.getMaxMark() > 0 : option.getMaxMark() > correctAnswersGroup.getMaxMark()) { correctAnswersGroup = option; } @@ -1174,7 +1178,8 @@ // add mark only if an item was unravelled if (isItemUnraveled(item, userLogs)) { int itemAttempts = ScratchieServiceImpl.getNumberAttemptsForItem(item, userLogs); - String markStr = (itemAttempts <= presetMarks.length) ? presetMarks[itemAttempts - 1] + String markStr = (itemAttempts <= presetMarks.length) + ? presetMarks[itemAttempts - 1] : presetMarks[presetMarks.length - 1]; mark = Double.valueOf(markStr); } @@ -1192,9 +1197,8 @@ // if VS answer was marked as correct in Scratchie after leader chose another answer, // then the subsequent answers do not count if (qbQuestion.getType().equals(QbQuestion.TYPE_VERY_SHORT_ANSWERS)) { - QbOption correctAnswersGroup = qbQuestion.getQbOptions().get(0).isCorrect() - ? qbQuestion.getQbOptions().get(0) - : qbQuestion.getQbOptions().get(1); + QbOption correctAnswersGroup = qbQuestion.getQbOptions().get(0).isCorrect() ? qbQuestion.getQbOptions() + .get(0) : qbQuestion.getQbOptions().get(1); correctVsaOption = correctAnswersGroup.getName(); } for (ScratchieAnswerVisitLog userLog : userLogs) { @@ -1227,8 +1231,8 @@ GroupSummary groupSummary = new GroupSummary(session); List sessionAttempts = scratchieAnswerVisitDao.getLogsBySessionAndItem(sessionId, itemUid); - int numberColumns = options.size() > sessionAttempts.size() || isMcqItem ? options.size() - : sessionAttempts.size(); + int numberColumns = + options.size() > sessionAttempts.size() || isMcqItem ? options.size() : sessionAttempts.size(); groupSummary.setNumberColumns(numberColumns); Map optionMap = new HashMap<>(); @@ -1313,8 +1317,8 @@ Set items = new TreeSet<>(new ScratchieItemComparator()); items.addAll(scratchie.getScratchieItems()); - List burningQuestionDtos = scratchieBurningQuestionDao - .getBurningQuestionsByContentId(scratchie.getUid(), sessionId); + List burningQuestionDtos = scratchieBurningQuestionDao.getBurningQuestionsByContentId( + scratchie.getUid(), sessionId); //in order to group BurningQuestions by items, organise them as a list of BurningQuestionItemDTOs List burningQuestionItemDtos = new ArrayList<>(); @@ -1326,8 +1330,8 @@ ScratchieBurningQuestion burningQuestion = burningQuestionDto.getBurningQuestion(); //general burning question is handled further down - if (!burningQuestion.isGeneralQuestion() - && item.getUid().equals(burningQuestion.getScratchieItem().getUid())) { + if (!burningQuestion.isGeneralQuestion() && item.getUid() + .equals(burningQuestion.getScratchieItem().getUid())) { burningQuestionDtosOfSpecifiedItem.add(burningQuestionDto); } } @@ -1855,7 +1859,8 @@ continue; } row = researchAndAnalysisSheet.initRow(); - String optionTitle = isMcqItem ? removeHtmlMarkup(optionDto.getAnswer()) + String optionTitle = isMcqItem + ? removeHtmlMarkup(optionDto.getAnswer()) : optionDto.getAnswer().strip().replace("\r\n", ", "); if (optionDto.isCorrect()) { optionTitle += "(" + getMessage("label.monitoring.item.summary.correct") + ")"; @@ -1902,8 +1907,8 @@ //build list of all logs left for this item and this session List logsBySessionAndItem = new ArrayList<>(); for (ScratchieAnswerVisitLog log : logs) { - if (log.getSessionId().equals(sessionId) - && log.getQbToolQuestion().getUid().equals(item.getUid())) { + if (log.getSessionId().equals(sessionId) && log.getQbToolQuestion().getUid() + .equals(item.getUid())) { logsBySessionAndItem.add(log); } } @@ -1946,8 +1951,8 @@ int logsBySessionAndItem = 0; for (ScratchieAnswerVisitLog log : logs) { - if (log.getSessionId().equals(sessionId) - && log.getQbToolQuestion().getUid().equals(item.getUid())) { + if (log.getSessionId().equals(sessionId) && log.getQbToolQuestion().getUid() + .equals(item.getUid())) { logsBySessionAndItem++; } } @@ -2007,7 +2012,8 @@ for (OptionDTO option : options) { if (option.isCorrect()) { correctOption = option.getAnswer(); - correctOption = isMcqItem ? removeHtmlMarkup(correctOption) + correctOption = isMcqItem + ? removeHtmlMarkup(correctOption) : correctOption.strip().replace("\r\n", ", "); } } @@ -2033,8 +2039,8 @@ //build list of all logs left for this item and this session List logsBySessionAndItem = new ArrayList<>(); for (ScratchieAnswerVisitLog log : logs) { - if (log.getSessionId().equals(sessionId) - && log.getQbToolQuestion().getUid().equals(itemDto.getUid())) { + if (log.getSessionId().equals(sessionId) && log.getQbToolQuestion().getUid() + .equals(itemDto.getUid())) { logsBySessionAndItem.add(log); } } @@ -2190,16 +2196,17 @@ summary.setMark(numberOfFirstChoiceEvents); // round the percentage cell - String totalPercentage = String - .valueOf((items.size() == 0) ? 0 : (double) numberOfFirstChoiceEvents * 100 / items.size()); + String totalPercentage = String.valueOf( + (items.size() == 0) ? 0 : (double) numberOfFirstChoiceEvents * 100 / items.size()); summary.setTotalPercentage(Double.valueOf(totalPercentage)); } model.put("sessionDtos", groupSummaries); boolean vsaPresent = false; for (ScratchieItem item : itemList) { - item.setCorrectOnFirstAttemptPercent(groupSummaries.isEmpty() ? 0 + item.setCorrectOnFirstAttemptPercent(groupSummaries.isEmpty() + ? 0 : (double) item.getCorrectOnFirstAttemptCount() * 100 / groupSummaries.size()); if (!vsaPresent && item.getQbQuestion().getType().equals(QbQuestion.TYPE_VERY_SHORT_ANSWERS)) { @@ -2293,8 +2300,10 @@ boolean isCorrect = isItemUnraveled(item, visitLog); boolean isFirstAnswersGroupCorrect = qbQuestion.getQbOptions().get(0).isCorrect(); - sequencialLetter = isCorrect && isFirstAnswersGroupCorrect - || !isCorrect && !isFirstAnswersGroupCorrect ? "A" : "B"; + sequencialLetter = + isCorrect && isFirstAnswersGroupCorrect || !isCorrect && !isFirstAnswersGroupCorrect + ? "A" + : "B"; } optionsSequence += optionsSequence.isEmpty() ? sequencialLetter : ", " + sequencialLetter; @@ -2432,9 +2441,9 @@ for (Long newQuestionUid : newQuestionUids) { QbQuestion newQuestion = qbService.getQuestionByUid(newQuestionUid); - if (!(newQuestion.getType().equals(QbQuestion.TYPE_MULTIPLE_CHOICE) - || newQuestion.getType().equals(QbQuestion.TYPE_MARK_HEDGING) - || newQuestion.getType().equals(QbQuestion.TYPE_VERY_SHORT_ANSWERS))) { + if (!(newQuestion.getType().equals(QbQuestion.TYPE_MULTIPLE_CHOICE) || newQuestion.getType() + .equals(QbQuestion.TYPE_MARK_HEDGING) || newQuestion.getType() + .equals(QbQuestion.TYPE_VERY_SHORT_ANSWERS))) { log.warn("QB question with UID " + newQuestionUid + " is not supported by TBL tRAT, skipping"); continue; } @@ -2519,8 +2528,9 @@ public void changeLeaderForGroup(long toolSessionId, long leaderUserId) { ScratchieSession session = getScratchieSessionBySessionId(toolSessionId); if (session.isScratchingFinished()) { - throw new InvalidParameterException("Attempting to assing a new leader with user ID " + leaderUserId - + " to a finished session wtih ID " + toolSessionId); + throw new InvalidParameterException( + "Attempting to assing a new leader with user ID " + leaderUserId + " to a finished session wtih ID " + + toolSessionId); } ScratchieUser existingLeader = session.getGroupLeader(); @@ -2539,8 +2549,9 @@ + toolSessionId); } } else if (!newLeader.getSession().getSessionId().equals(toolSessionId)) { - throw new InvalidParameterException("User with ID " + leaderUserId + " belongs to session with ID " - + newLeader.getSession().getSessionId() + " and not to session with ID " + toolSessionId); + throw new InvalidParameterException( + "User with ID " + leaderUserId + " belongs to session with ID " + newLeader.getSession() + .getSessionId() + " and not to session with ID " + toolSessionId); } session.setGroupLeader(newLeader); @@ -2852,8 +2863,9 @@ } else { log.error("Fail to leave tool Session.Could not find shared scratchie " + "session by given session id: " + toolSessionId); - throw new DataMissingException("Fail to leave tool Session." - + "Could not find shared scratchie session by given session id: " + toolSessionId); + throw new DataMissingException( + "Fail to leave tool Session." + "Could not find shared scratchie session by given session id: " + + toolSessionId); } return toolService.completeToolSession(toolSessionId, learnerId); } @@ -2999,7 +3011,8 @@ return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); } - return new ToolCompletionStatus(learner.isSessionFinished() ? ToolCompletionStatus.ACTIVITY_COMPLETED + return new ToolCompletionStatus(learner.isSessionFinished() + ? ToolCompletionStatus.ACTIVITY_COMPLETED : ToolCompletionStatus.ACTIVITY_ATTEMPTED, null, null); } // ****************** REST methods ************************* @@ -3067,25 +3080,30 @@ qbQuestion = null; } - Long collectionUid = JsonUtil.optLong(questionData, RestTags.COLLECTION_UID); - if (collectionUid == null) { - // if no collection UUID was specified, questions end up in user's private collection - if (privateCollectionUUID == null) { - privateCollectionUUID = qbService.getUserPrivateCollection(userID).getUid(); + boolean addToCollection = qbQuestion == null; + if (addToCollection) { + Long collectionUid = JsonUtil.optLong(toolContentJSON, RestTags.COLLECTION_UID); + if (collectionUid == null) { + // if no collection UUID was specified, questions end up in user's private collection + if (privateCollectionUUID == null) { + privateCollectionUUID = qbService.getUserPrivateCollection(userID).getUid(); + } + collectionUid = privateCollectionUUID; } - collectionUid = privateCollectionUUID; - } - boolean addToCollection = true; - // check if it is the same collection - there is a good chance it is - if (collection == null || collectionUid != collection.getUid()) { - collection = qbService.getCollection(collectionUid); - if (collection == null) { + // check if it is the same collection - there is a good chance it is + if (collection == null || collectionUid != collection.getUid()) { + collection = qbService.getCollection(collectionUid); + if (collection == null) { + addToCollection = false; + } else { + collectionUUIDs = qbService.getCollectionQuestions(collection.getUid()).stream() + .peek(q -> qbService.releaseFromCache(q)).filter(q -> q.getUuid() != null) + .collect(Collectors.mapping(q -> q.getUuid().toString(), Collectors.toSet())); + } + } + if (collectionUUIDs.contains(uuid)) { addToCollection = false; - } else { - collectionUUIDs = qbService.getCollectionQuestions(collection.getUid()).stream() - .peek(q -> qbService.releaseFromCache(q)).filter(q -> q.getUuid() != null) - .collect(Collectors.mapping(q -> q.getUuid().toString(), Collectors.toSet())); } } @@ -3138,8 +3156,6 @@ userManagementService.save(outcomeMapping); } } - } else if (addToCollection && collectionUUIDs.contains(uuid)) { - addToCollection = false; } item.setQbQuestion(qbQuestion); Index: lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/WhiteboardService.java =================================================================== diff -u -r5b9f590b301c276f8df06b30c26981b0eb634e69 -r5bc88174180046cd153cfc46a0c8ef13675bd4bf --- lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/WhiteboardService.java (.../WhiteboardService.java) (revision 5b9f590b301c276f8df06b30c26981b0eb634e69) +++ lams_tool_whiteboard/src/java/org/lamsfoundation/lams/tool/whiteboard/service/WhiteboardService.java (.../WhiteboardService.java) (revision 5bc88174180046cd153cfc46a0c8ef13675bd4bf) @@ -23,26 +23,8 @@ package org.lamsfoundation.lams.tool.whiteboard.service; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.URLEncoder; -import java.nio.charset.Charset; -import java.security.InvalidParameterException; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.function.Function; -import java.util.stream.Collectors; - +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -63,12 +45,7 @@ import org.lamsfoundation.lams.rating.model.RatingCriteria; import org.lamsfoundation.lams.rating.model.ToolActivityRatingCriteria; import org.lamsfoundation.lams.rating.service.IRatingService; -import org.lamsfoundation.lams.tool.ToolCompletionStatus; -import org.lamsfoundation.lams.tool.ToolContentManager; -import org.lamsfoundation.lams.tool.ToolOutput; -import org.lamsfoundation.lams.tool.ToolOutputDefinition; -import org.lamsfoundation.lams.tool.ToolSessionExportOutputData; -import org.lamsfoundation.lams.tool.ToolSessionManager; +import org.lamsfoundation.lams.tool.*; import org.lamsfoundation.lams.tool.exception.DataMissingException; import org.lamsfoundation.lams.tool.exception.ToolException; import org.lamsfoundation.lams.tool.service.ILamsToolService; @@ -92,8 +69,15 @@ import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.WebUtil; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.security.InvalidParameterException; +import java.time.LocalDateTime; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; public class WhiteboardService implements IWhiteboardService, ToolContentManager, ToolSessionManager { private static Logger log = Logger.getLogger(WhiteboardService.class.getName()); @@ -183,8 +167,9 @@ public void changeLeaderForGroup(long toolSessionId, long leaderUserId) { WhiteboardSession session = getWhiteboardSessionBySessionId(toolSessionId); if (WhiteboardConstants.COMPLETED == session.getStatus()) { - throw new InvalidParameterException("Attempting to assing a new leader with user ID " + leaderUserId - + " to a finished session wtih ID " + toolSessionId); + throw new InvalidParameterException( + "Attempting to assing a new leader with user ID " + leaderUserId + " to a finished session wtih ID " + + toolSessionId); } WhiteboardUser existingLeader = session.getGroupLeader(); @@ -227,9 +212,13 @@ WhiteboardSession session = user.getSession(); Whiteboard whiteboard = session.getWhiteboard(); - LocalDateTime launchedDate = LocalDateTime.now(); - user.setTimeLimitLaunchedDate(launchedDate); - whiteboardUserDao.update(user); + LocalDateTime launchedDate = user.getTimeLimitLaunchedDate(); + if (launchedDate == null) { + launchedDate = LocalDateTime.now(); + user.setTimeLimitLaunchedDate(launchedDate); + whiteboardUserDao.update(user); + } + // if the user is not a leader, store his launch date, but return null so the leader's launch date is in use if (!whiteboard.isUseSelectLeaderToolOuput() || (session.getGroupLeader() != null && session.getGroupLeader().getUserId().equals(Long.valueOf(userId)))) { @@ -326,8 +315,9 @@ } List groupList = new ArrayList<>(); - Long userSessionId = ratingUserId == null || !whiteboard.isGalleryWalkStarted() - || !whiteboard.isGalleryWalkEditEnabled() ? null + Long userSessionId = + ratingUserId == null || !whiteboard.isGalleryWalkStarted() || !whiteboard.isGalleryWalkEditEnabled() + ? null : getUserByIDAndContent(ratingUserId, contentId).getSession().getSessionId(); for (WhiteboardSession session : sessionList) { // one new group for one session. @@ -339,10 +329,10 @@ String wid = whiteboard.getContentId() + "-" + session.getSessionId(); wid = getWhiteboardPrefixedId(wid); - + // show read only pad if it is a learner and no reedit was enabled - if (ratingUserId != null && (userSessionId == null || !session.getSessionId().equals(userSessionId) - || (whiteboard.isUseSelectLeaderToolOuput() && (session.getGroupLeader() == null + if (ratingUserId != null && (userSessionId == null || !session.getSessionId().equals(userSessionId) || ( + whiteboard.isUseSelectLeaderToolOuput() && (session.getGroupLeader() == null || !session.getGroupLeader().getUserId().equals(ratingUserId))))) { wid = getWhiteboardReadOnlyWid(wid); } @@ -396,7 +386,8 @@ if (entry != null) { ReflectDTO ref = new ReflectDTO(user); ref.setReflect(entry.getEntry()); - Date postedDate = (entry.getLastModified() != null) ? entry.getLastModified() + Date postedDate = (entry.getLastModified() != null) + ? entry.getLastModified() : entry.getCreateDate(); ref.setDate(postedDate); reflections.add(ref); @@ -438,8 +429,8 @@ @Override public Grouping getGrouping(long toolContentId) { - ToolActivity toolActivity = (ToolActivity) userManagementService - .findByProperty(ToolActivity.class, "toolContentId", toolContentId).get(0); + ToolActivity toolActivity = (ToolActivity) userManagementService.findByProperty(ToolActivity.class, + "toolContentId", toolContentId).get(0); return toolActivity.getApplyGrouping() ? toolActivity.getGrouping() : null; } @@ -467,8 +458,8 @@ } if (criteria.isEmpty()) { - ToolActivityRatingCriteria criterion = (ToolActivityRatingCriteria) RatingCriteria - .getRatingCriteriaInstance(RatingCriteria.TOOL_ACTIVITY_CRITERIA_TYPE); + ToolActivityRatingCriteria criterion = (ToolActivityRatingCriteria) RatingCriteria.getRatingCriteriaInstance( + RatingCriteria.TOOL_ACTIVITY_CRITERIA_TYPE); criterion.setTitle(messageService.getMessage("label.pad.rating.title")); criterion.setOrderId(1); criterion.setRatingStyle(RatingCriteria.RATING_STYLE_STAR); @@ -552,8 +543,8 @@ @Override public String getWhiteboardServerUrl() throws WhiteboardApplicationException { WhiteboardConfigItem whiteboardServerUrlConfigItem = getConfigItem(WhiteboardConfigItem.KEY_SERVER_URL); - if (whiteboardServerUrlConfigItem == null - || StringUtils.isBlank(whiteboardServerUrlConfigItem.getConfigValue())) { + if (whiteboardServerUrlConfigItem == null || StringUtils.isBlank( + whiteboardServerUrlConfigItem.getConfigValue())) { throw new WhiteboardApplicationException( "Whiteboard server URL is not configured on appadmin tool management page"); } @@ -575,8 +566,8 @@ return null; } WhiteboardConfigItem whiteboardAccessTokenConfigItem = getConfigItem(WhiteboardConfigItem.KEY_ACCESS_TOKEN); - if (whiteboardAccessTokenConfigItem == null - || StringUtils.isBlank(whiteboardAccessTokenConfigItem.getConfigValue())) { + if (whiteboardAccessTokenConfigItem == null || StringUtils.isBlank( + whiteboardAccessTokenConfigItem.getConfigValue())) { return null; } // sourceWid is present when we want to copy content from other canvas @@ -958,14 +949,14 @@ @Override public void removeLearnerContent(Long toolContentId, Integer userId) throws ToolException { if (WhiteboardService.log.isDebugEnabled()) { - WhiteboardService.log - .debug("Removing Whiteboard content for user ID " + userId + " and toolContentId " + toolContentId); + WhiteboardService.log.debug( + "Removing Whiteboard content for user ID " + userId + " and toolContentId " + toolContentId); } Whiteboard whiteboard = whiteboardDao.getByContentId(toolContentId); if (whiteboard == null) { - WhiteboardService.log - .warn("Did not find activity with toolContentId: " + toolContentId + " to remove learner content"); + WhiteboardService.log.warn( + "Did not find activity with toolContentId: " + toolContentId + " to remove learner content"); return; } @@ -1002,7 +993,8 @@ return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); } - return new ToolCompletionStatus(learner.isSessionFinished() ? ToolCompletionStatus.ACTIVITY_COMPLETED + return new ToolCompletionStatus(learner.isSessionFinished() + ? ToolCompletionStatus.ACTIVITY_COMPLETED : ToolCompletionStatus.ACTIVITY_ATTEMPTED, null, null); } @@ -1022,8 +1014,8 @@ session.setStatus(WhiteboardConstants.COMPLETED); whiteboardSessionDao.update(session); } else { - WhiteboardService.log - .error("Fail to leave tool Session. Could not find Whiteboard session by given session id: " + WhiteboardService.log.error( + "Fail to leave tool Session. Could not find Whiteboard session by given session id: " + toolSessionId); throw new DataMissingException( "Fail to leave tool Session. Could not find Whiteboard session by given session id: "