-
\ No newline at end of file
Index: lams_monitoring/web/includes/javascript/monitorLesson.js
===================================================================
diff -u -rd0f4c3bdd871e236755472c8443c337b2b96e48c -r330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82
--- lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision d0f4c3bdd871e236755472c8443c337b2b96e48c)
+++ lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82)
@@ -293,61 +293,6 @@
$('#forceBackwardsDialog').modal('hide');
});
-
- $('#presenceButton').change(function(){
- var checked = $(this).prop('checked'),
- data = {
- 'presenceAvailable' : checked,
- 'lessonID' : lessonId
- };
- data[csrfTokenName] = csrfTokenValue;
- $.ajax({
- url : LAMS_URL + 'monitoring/monitoring/presenceAvailable.do',
- type : 'POST',
- cache : false,
- data : data,
- success : function() {
- // updatePresenceAvailableCount();
- if (checked) {
- $('#imButtonWrapper').show();
- showToast(LABELS.LESSON_PRESENCE_ENABLE_ALERT);
- } else {
- $('#imButtonWrapper, #openImButton').hide();
- $('#imButton').prop('checked', false);
- showToast(LABELS.LESSON_PRESENCE_DISABLE_ALERT);
- }
- }
- });
- });
-
- // sets instant messaging availability
- $('#imButton').click(function(){
- var checked = $(this).prop('checked'),
- data = {
- 'presenceImAvailable' : checked,
- 'lessonID' : lessonId
- };
- data[csrfTokenName] = csrfTokenValue;
- $.ajax({
- url : LAMS_URL + 'monitoring/monitoring/presenceImAvailable.do',
- type : 'POST',
- cache : false,
- data : data,
- success : function() {
- if (checked) {
- $('#openImButton').show();
- $('#openImButton').prop('disabled', false);
- showToast(LABELS.LESSON_IM_ENABLE_ALERT);
- } else {
- $('#openImButton').hide();
- showToast(LABELS.LESSON_IM_DISABLE_ALERT);
- }
- }
- });
- });
-
- $('#openImButton').click(openChatWindow);
-
//enable renaming of lesson title
$('#lesson-name').editable({
type: 'text',
@@ -465,6 +410,7 @@
},
success : function(response) {
+
// update lesson state label
lessonStateId = +response.lessonStateID;
var label = null,
@@ -532,17 +478,19 @@
lessonFinishDateSpan = $('#lessonFinishDateSpan'),
lessonStateChanger = $('#lessonStateChanger'),
stateLabel = $('#lessonStateLabel');
+
switch (lessonStateId) {
- //created but not started lesson
+ // created but not started lesson
case 1:
scheduleControls.css('display','inline');
if ( response.finishDate ) {
lessonFinishDateSpan.text(LABELS.LESSON_FINISH.replace("%0",response.finishDate)).css('display','inline');
$("#scheduleDisableLessonButton").html(LABELS.RESCHEDULE);
$("#disableLessonButton").css('display', 'none');
+ } else {
+ lessonFinishDateSpan.hide();
}
startDateField.hide();
- lessonFinishDateSpan.hide();
lessonStateChanger.hide();
break;
//scheduled lesson
@@ -1032,7 +980,7 @@
cache : false,
type : 'POST',
success : function() {
- loadTab();
+ document.location.reload();
}
});
}
@@ -1051,16 +999,6 @@
return list;
}
-
-function openChatWindow(){
- // variables are set in JSP page
- window.open(LAMS_URL + 'learning/presenceChat.jsp?lessonID=' + lessonId
- + '&presenceEnabledPatch=true&presenceImEnabled=true&presenceShown=true&createDateTime='
- + createDateTimeStr
- ,'Chat'
- ,'width=650,height=350,resizable=no,scrollbars=no,status=no,menubar=no,toolbar=no');
-}
-
function showEmailDialog(userId){
//check whether current window is a top level one (otherwise it's an iframe or popup)
@@ -1089,28 +1027,6 @@
}, false, true);
}
-/*
-function updatePresenceAvailableCount(){
- var checked = $('#presenceButton').prop('checked');
- counter = $('#presenceCounter');
- if (checked) {
- $.ajax({
- dataType : 'text',
- url : LAMS_URL + 'learning/learner/getPresenceChatActiveUserCount.do?',
- cache : false,
- data : {
- 'lessonID' : lessonId
- },
- success : function(result) {
- counter.text(result).show();
- }
- });
- } else {
- counter.hide();
- }
-}
-*/
-
function updateContributeActivities(contributeActivities) {
let requiredTasksPanel = $('#required-tasks'),
requiredTasksContent = $('#required-tasks-content', requiredTasksPanel);
Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java
===================================================================
diff -u -rd0f4c3bdd871e236755472c8443c337b2b96e48c -r330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82
--- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision d0f4c3bdd871e236755472c8443c337b2b96e48c)
+++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82)
@@ -35,6 +35,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -154,6 +155,7 @@
implements IAssessmentService, ICommonAssessmentService, ToolContentManager, ToolSessionManager,
ToolRestManager, IQbToolService {
private static Logger log = Logger.getLogger(AssessmentServiceImpl.class.getName());
+ private static Logger logAutosave = Logger.getLogger(AssessmentServiceImpl.class.getName() + "_autosave");
private AssessmentDAO assessmentDao;
@@ -812,6 +814,11 @@
assessmentResultDao.update(result);
+ if (!isAutosave && assessment.getTimeLimitAdjustments().containsKey(userId.intValue())) {
+ // make time widget stop displaying individual extension for this user
+ FluxRegistry.emit(AssessmentConstants.TIME_LIMIT_PANEL_UPDATE_SINK_NAME, assessment.getContentId());
+ }
+
// refresh non-leaders when leader changed his answers or submitted them
if (assessment.isUseSelectLeaderToolOuput() && (!isAutosave || isAnswerModified)) {
AssessmentSession session = getSessionBySessionId(result.getSessionId());
@@ -850,11 +857,41 @@
}
}
+ StringBuilder autosaveLogBuilder = null;
+ if (StringUtils.isNotBlank(questionResult.getAnswer()) && "".equals(questionDto.getAnswer())) {
+ autosaveLogBuilder = new StringBuilder("For learner ").append(assessmentResult.getUser().getUid())
+ .append(" \"").append(assessmentResult.getUser().getLoginName()).append("\" for question ")
+ .append(questionDto.getUid()).append(" for question result ").append(questionResult.getUid())
+ .append(" answer was \"").append(questionResult.getAnswer())
+ .append("\" and it is now blank, skipping save.");
+ log.warn(autosaveLogBuilder);
+ if (logAutosave.isTraceEnabled()) {
+ logAutosave.trace(autosaveLogBuilder);
+ }
+ questionResult.setAnswerModified(false);
+ return questionResult;
+ }
+
boolean isAnswerModified =
!Objects.equals(questionResult.getAnswerBoolean(), questionDto.getAnswerBoolean()) || !Objects.equals(
questionResult.getAnswerFloat(), questionDto.getAnswerFloat()) || !Objects.equals(
questionResult.getAnswer(), questionDto.getAnswer());
+ // this is for logging every autosave as requested by Imperial
+ // it produces a lot of logs, so it goes to a separate file
+
+ if (logAutosave.isTraceEnabled()) {
+ autosaveLogBuilder = new StringBuilder("For learner ").append(assessmentResult.getUser().getUid())
+ .append(" \"").append(assessmentResult.getUser().getLoginName()).append("\" for question ")
+ .append(questionDto.getUid()).append(" for question result ").append(questionResult.getUid())
+ .append(" answer was \"").append(questionResult.getAnswer()).append("\" and it is now \"")
+ .append(questionDto.getAnswer()).append("\", answerBoolean was \"")
+ .append(questionResult.getAnswerBoolean()).append("\" and it is now \"")
+ .append(questionDto.getAnswerBoolean()).append("\", answerFloat was \"")
+ .append(questionResult.getAnswerFloat()).append("\" and it is now \"")
+ .append(questionDto.getAnswerFloat()).append("\"");
+ }
+
// store question answer values
questionResult.setAnswerBoolean(questionDto.getAnswerBoolean());
questionResult.setAnswerFloat(questionDto.getAnswerFloat());
@@ -882,6 +919,12 @@
isAnswerModified |= !Objects.equals(optionAnswer.getAnswerBoolean(), optionDto.getAnswerBoolean());
}
+ if (logAutosave.isTraceEnabled()) {
+ autosaveLogBuilder.append(", for option ").append(optionDto.getUid()).append(" option result ")
+ .append(optionAnswer.getUid()).append(" was \"").append(optionAnswer.getAnswerBoolean())
+ .append("\" and it is now \"").append(optionDto.getAnswerBoolean()).append("\"");
+ }
+
// store option answer values
optionAnswer.setAnswerBoolean(optionDto.getAnswerBoolean());
if (questionDto.getType() == QbQuestion.TYPE_ORDERING) {
@@ -893,15 +936,20 @@
}
}
+ if (logAutosave.isTraceEnabled()) {
+ logAutosave.trace(autosaveLogBuilder);
+ }
+
// store confidence levels entered by the learner
if (assessment.isEnableConfidenceLevels()) {
isAnswerModified |= !Objects.equals(questionResult.getConfidenceLevel(), questionDto.getConfidenceLevel());
questionResult.setConfidenceLevel(questionDto.getConfidenceLevel());
}
// store justification entered by the learner
- if (assessment.isAllowAnswerJustification() || (questionDto.getType().equals(QbQuestion.TYPE_MARK_HEDGING)
- && questionDto.isHedgingJustificationEnabled())) {
+ if (assessment.isAllowAnswerJustification() || (questionDto.getType().
+
+ equals(QbQuestion.TYPE_MARK_HEDGING) && questionDto.isHedgingJustificationEnabled())) {
isAnswerModified |= !Objects.equals(questionResult.getJustification(), questionDto.getJustification());
questionResult.setJustification(questionDto.getJustification());
}
@@ -1441,13 +1489,14 @@
if (!results.isEmpty()) {
//prepare list of the questions to display, filtering out questions that aren't supposed to be answered
- Set questions = new TreeSet<>();
+ Set questions = null;
//in case there is at least one random question - we need to show all questions in a drop down select
if (assessment.hasRandomQuestion()) {
- questions.addAll(assessment.getQuestions());
+ questions = new TreeSet<>(assessment.getQuestions());
//otherwise show only questions from the question list
} else {
+ questions = new LinkedHashSet<>();
for (QuestionReference reference : assessment.getQuestionReferences()) {
questions.add(reference.getQuestion());
}
@@ -3042,9 +3091,9 @@
}
}
- // *****************************************************************************
- // private methods
- // *****************************************************************************
+// *****************************************************************************
+// private methods
+// *****************************************************************************
private Assessment getDefaultAssessment() throws AssessmentApplicationException {
Long defaultAssessmentId = getToolDefaultContentIdBySignature(AssessmentConstants.TOOL_SIGNATURE);
@@ -3068,9 +3117,9 @@
return contentId;
}
- // *****************************************************************************
- // set methods for Spring Bean
- // *****************************************************************************
+// *****************************************************************************
+// set methods for Spring Bean
+// *****************************************************************************
public void setLogEventService(ILogEventService logEventService) {
this.logEventService = logEventService;
@@ -3116,9 +3165,9 @@
this.assessmentConfigDao = assessmentConfigDao;
}
- // *******************************************************************************
- // ToolContentManager, ToolSessionManager methods
- // *******************************************************************************
+// *******************************************************************************
+// ToolContentManager, ToolSessionManager methods
+// *******************************************************************************
@Override
public void exportToolContent(Long toolContentId, String rootPath) throws DataMissingException, ToolException {
@@ -3786,6 +3835,7 @@
assessment.setAllowQuestionFeedback(
JsonUtil.optBoolean(toolContentJSON, "allowQuestionFeedback", Boolean.FALSE));
assessment.setAllowDiscloseAnswers(JsonUtil.optBoolean(toolContentJSON, "allowDiscloseAnswers", Boolean.FALSE));
+ assessment.setAllowDiscloseAnswers(JsonUtil.optBoolean(toolContentJSON, "allowAnswerRating", Boolean.TRUE));
assessment.setAllowRightAnswersAfterQuestion(
JsonUtil.optBoolean(toolContentJSON, "allowRightAnswersAfterQuestion", Boolean.FALSE));
assessment.setAllowWrongAnswersAfterQuestion(
Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java
===================================================================
diff -u -rd0f4c3bdd871e236755472c8443c337b2b96e48c -r330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82
--- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision d0f4c3bdd871e236755472c8443c337b2b96e48c)
+++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/LearningController.java (.../LearningController.java) (revision 330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82)
@@ -74,6 +74,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@@ -293,7 +294,7 @@
//user is allowed to answer questions if assessment activity doesn't have leaders or he is the leader
boolean hasEditRight =
- !assessment.isUseSelectLeaderToolOuput() || assessment.isUseSelectLeaderToolOuput() && isUserLeader;
+ (!assessment.isUseSelectLeaderToolOuput() || assessment.isUseSelectLeaderToolOuput() && isUserLeader) && !mode.isTeacher();
//showResults if user has finished the last result
boolean showResults = (lastResult != null) && (lastResult.getFinishDate() != null);
@@ -463,7 +464,7 @@
/**
* Shows next page. It's available only to leaders as non-leaders see all questions on one page.
*/
- @RequestMapping("/nextPage")
+ @PostMapping("/nextPage")
public String nextPage(HttpServletRequest request)
throws ServletException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
return nextPage(request, false, -1);
@@ -585,7 +586,7 @@
* @throws IllegalAccessException
*/
@SuppressWarnings("unchecked")
- @RequestMapping("/submitAll")
+ @PostMapping("/submitAll")
public String submitAll(HttpServletRequest request)
throws ServletException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
SessionMap sessionMap = getSessionMap(request);
@@ -688,7 +689,7 @@
/**
* auto saves responses
*/
- @RequestMapping("/autoSaveAnswers")
+ @PostMapping("/autoSaveAnswers")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public String autoSaveAnswers(HttpServletRequest request, HttpServletResponse response)
Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java
===================================================================
diff -u -r0b1d534ce1915b907afff0171909f90226b31921 -r330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82
--- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 0b1d534ce1915b907afff0171909f90226b31921)
+++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/controller/MonitoringController.java (.../MonitoringController.java) (revision 330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82)
@@ -357,7 +357,7 @@
String gradeString = request.getParameter(AssessmentConstants.PARAM_GRADE);
if (StringUtils.isNotBlank(gradeString) && !gradeString.strip().equals("-")) {
newGrade = Float.valueOf(gradeString);
- responseText = teacher.getLastName() + " " + teacher.getFirstName();
+ responseText = teacher.getFullName();
}
} else if (column.equals(AssessmentConstants.PARAM_MARKER_COMMENT)) {
markerComment = request.getParameter(AssessmentConstants.PARAM_MARKER_COMMENT);
@@ -484,7 +484,7 @@
ArrayNode userData = JsonNodeFactory.instance.arrayNode();
userData.add(userDto.getUserId());
userData.add(userDto.getSessionId());
- String fullName = HtmlUtils.htmlEscape(userDto.getFirstName() + " " + userDto.getLastName());
+ String fullName = HtmlUtils.htmlEscape(userDto.getFullName());
userData.add(fullName);
userData.add(userDto.getGrade());
if (userDto.getPortraitId() != null) {
@@ -594,7 +594,7 @@
for (AssessmentUserDTO userDto : userDtos) {
Long questionResultUid = userDto.getQuestionResultUid();
- String fullName = HtmlUtils.htmlEscape(userDto.getFirstName() + " " + userDto.getLastName());
+ String fullName = HtmlUtils.htmlEscape(userDto.getFullName());
ArrayNode userData = JsonNodeFactory.instance.arrayNode();
if (questionResultUid != null) {
@@ -1005,7 +1005,7 @@
ObjectNode userJSON = JsonNodeFactory.instance.objectNode();
userJSON.put("value", "user-" + user.getUserId());
- String name = user.getFirstName() + " " + user.getLastName() + " (" + user.getLogin() + ")";
+ String name = user.getFullName() + " (" + user.getLogin() + ")";
if (grouping != null) {
Group group = grouping.getGroupBy(user);
if (group != null && !group.isNull()) {
@@ -1058,7 +1058,7 @@
userJSON.put("userId", user.getUserId());
userJSON.put("adjustment", timeLimitAdjustments.get(user.getUserId().intValue()));
- String name = user.getFirstName() + " " + user.getLastName() + " (" + user.getLogin() + ")";
+ String name = user.getFullName() + " (" + user.getLogin() + ")";
if (grouping != null) {
Group group = grouping.getGroupBy(user);
if (group != null && !group.isNull()) {
Index: lams_tool_assessment/web/pages/learning/learning.jsp
===================================================================
diff -u -rd0f4c3bdd871e236755472c8443c337b2b96e48c -r330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82
--- lams_tool_assessment/web/pages/learning/learning.jsp (.../learning.jsp) (revision d0f4c3bdd871e236755472c8443c337b2b96e48c)
+++ lams_tool_assessment/web/pages/learning/learning.jsp (.../learning.jsp) (revision 330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82)
@@ -112,34 +112,36 @@
});
}
- initWebsocket('assessmentTimeLimit${sessionMap.assessment.contentId}',
- ''.replace('http', 'ws')
- + 'learningWebsocket?toolContentID=${sessionMap.assessment.contentId}',
- function (e) {
- // read JSON object
- var input = JSON.parse(e.data);
+
+ initWebsocket('assessmentTimeLimit${sessionMap.assessment.contentId}',
+ ''.replace('http', 'ws') + 'learningWebsocket?toolContentID=${sessionMap.assessment.contentId}',
+ function (e) {
+ // read JSON object
+ var input = JSON.parse(e.data);
+
+ if (input.clearTimer == true) {
+ // teacher stopped the timer, destroy it
+ $('#countdown').countdown('destroy').remove();
+ } else {
+ // teacher updated the timer
+ var secondsLeft = +input.secondsLeft,
+ counterInitialised = $('#countdown').length > 0;
+
+ if (counterInitialised) {
+ // just set the new time
+ $('#countdown').countdown('option', 'until', secondsLeft + 'S');
+ } else {
+ // initialise the timer
+ displayCountdown(secondsLeft);
+ }
+ }
+
+ // reset ping timer
+ websocketPing('assessmentTimeLimit${sessionMap.assessment.contentId}', true);
+ }
+ );
+
- if (input.clearTimer == true) {
- // teacher stopped the timer, destroy it
- $('#countdown').countdown('destroy').remove();
- } else {
- // teacher updated the timer
- var secondsLeft = +input.secondsLeft,
- counterInitialised = $('#countdown').length > 0;
-
- if (counterInitialised) {
- // just set the new time
- $('#countdown').countdown('option', 'until', secondsLeft + 'S');
- } else {
- // initialise the timer
- displayCountdown(secondsLeft);
- }
- }
-
- // reset ping timer
- websocketPing('assessmentTimeLimit${sessionMap.assessment.contentId}', true);
- });
-
//autocomplete for VSA
$('.ui-autocomplete-input').each(function(){
$(this).autocomplete({
@@ -207,7 +209,6 @@
left: '',
right: '0%',
opacity: '.8',
- width: '230px',
cursor: 'default',
border: 'none'
}
@@ -232,11 +233,11 @@
var hours = $("#countdown").countdown('getTimes')[4];
var minutes = $("#countdown").countdown('getTimes')[5];
if (screenCountdown.data("hours") != hours || screenCountdown.data("minutes") != minutes) {
- var timeLeftText = " ";
+ var timeLeftText = " ";
if (hours > 0) {
- timeLeftText += hours + " ";
+ timeLeftText += hours + " ";
}
- timeLeftText += minutes + " ";
+ timeLeftText += minutes + " ";
screenCountdown.html(timeLeftText);
screenCountdown.data("hours", hours);
@@ -269,13 +270,14 @@
//autosave feature
- var autosaveInterval = ${isLeadershipEnabled and isUserLeader ? 10000 : 30000}; // 30 or 10 seconds interval
+ var autosaveInterval = ${isLeadershipEnabled and isUserLeader ? 10000 : 30000}, // 30 or 10 seconds interval
+ autosaveWindowId = new Date().getTime(); // all we need for this ID is to be unique
function learnerAutosave(isCommand){
// isCommand means that the autosave was triggered by force complete or another command websocket message
// in this case do not check multiple tabs open, just autosave
if (!isCommand) {
- let shouldAutosave = preventLearnerAutosaveFromMultipleTabs(autosaveInterval);
+ let shouldAutosave = preventLearnerAutosaveFromMultipleTabs(autosaveWindowId, autosaveInterval);
if (!shouldAutosave) {
return;
}
@@ -349,9 +351,9 @@
// validate only if time limit is not expired
// otherwise confirm with learner that he wants to submit
if (!isTimelimitExpired && (!validateAnswers()
- || (!isResubmitAllowed &&
- !confirm("")))) {
- return;
+ || (!isResubmitAllowed &&
+ !confirm("")))) {
+ return;
}
disableButtons();
@@ -616,10 +618,13 @@
-
-
-
+
+
+
+
+
+
<%@ include file="parts/paging.jsp"%>
Index: lams_tool_assessment/web/pages/learning/parts/allquestions.jsp
===================================================================
diff -u -rd0f4c3bdd871e236755472c8443c337b2b96e48c -r330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82
--- lams_tool_assessment/web/pages/learning/parts/allquestions.jsp (.../allquestions.jsp) (revision d0f4c3bdd871e236755472c8443c337b2b96e48c)
+++ lams_tool_assessment/web/pages/learning/parts/allquestions.jsp (.../allquestions.jsp) (revision 330b0d5f8fa4a8deb6d7454f92bdbd289e89cb82)
@@ -1,155 +1,156 @@
<%@ include file="/common/taglibs.jsp"%>
- <%-- Prepare same content for each question Etherpad. Each group participant's first and last name --%>
-
-
+ <%-- Prepare same content for each question Etherpad. Each group participant's first and last name --%>
+
+ :
-
-
-
-
+
+
+
+