Index: lams_central/conf/language/lams/ApplicationResources.properties
===================================================================
diff -u -r53dbc37b6825194501d9f178308323373eebc3fa -r3085af1c7e3e6c3496af23a748d998886d7168fd
--- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 53dbc37b6825194501d9f178308323373eebc3fa)
+++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 3085af1c7e3e6c3496af23a748d998886d7168fd)
@@ -1120,3 +1120,7 @@
label.qb.collection.remove.questions.tooltip = Remove all selected questions from the collection. If they are present only in this collection, they will be permanently removed.
label.qb.collection.remove.questions.fail = Questions can only be removed/deleted from the collection if they have not been used in an assessment activity. If the question is already in used, it will not be deleted.
label.authoring.short.answer.hint = In each option box type answers in separate lines.
+label.vsa.allocate.button = Allocate VSAs
+label.vsa.allocate.description = Allocate students' answers by dragging and dropping them to correct options
+label.vsa.deallocate.button.tip = Click to move answer back to queue
+label.vsa.deallocate.confirm = Are you sure you want to mark this answer as not correct? Students' scores will be recalculated.
Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/VsaController.java
===================================================================
diff -u
--- lams_central/src/java/org/lamsfoundation/lams/web/qb/VsaController.java (revision 0)
+++ lams_central/src/java/org/lamsfoundation/lams/web/qb/VsaController.java (revision 3085af1c7e3e6c3496af23a748d998886d7168fd)
@@ -0,0 +1,81 @@
+package org.lamsfoundation.lams.web.qb;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.lamsfoundation.lams.qb.service.IQbService;
+import org.lamsfoundation.lams.tool.service.ILamsToolService;
+import org.lamsfoundation.lams.web.util.AttributeNames;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+@Controller
+@RequestMapping("/qb/vsa")
+public class VsaController {
+
+ @Autowired
+ private IQbService qbService;
+
+ @Autowired
+ private ILamsToolService toolService;
+
+ @RequestMapping("/displayVsaAllocate")
+ public String displayVsaAllocate(@RequestParam(name = AttributeNames.PARAM_TOOL_CONTENT_ID) long toolContentId,
+ Model model) {
+
+ model.addAttribute("questions", toolService.getUnallocatedVSAnswers(toolContentId));
+ return "qb/vsa/vsaAllocate";
+ }
+
+ @RequestMapping(path = "/allocateUserAnswer", method = RequestMethod.POST)
+ @ResponseBody
+ public String allocateUserAnswer(HttpServletResponse response, @RequestParam Long toolQuestionUid,
+ @RequestParam Long targetOptionUid, @RequestParam Long previousOptionUid, @RequestParam String answer) {
+
+ Long optionUid = null;
+ boolean answerFoundInResults = false;
+
+ if (!targetOptionUid.equals(previousOptionUid) && StringUtils.isNotBlank(answer)) {
+ /*
+ * We need to synchronise this operation.
+ * When multiple requests are made to modify the same option, for example to add a VSA answer,
+ * we have a case of dirty reads.
+ * One answer gets added, but while DB is still flushing,
+ * another answer reads the option without the first answer,
+ * because it is not there yet.
+ * The second answer gets added, but the first one gets lost.
+ *
+ * We can not synchronise the method in service
+ * as the "dirty" transaction is already started before synchronisation kicks in.
+ * We do it here, before transaction starts.
+ * It will not work for distributed environment, though.
+ * If teachers allocate answers on different LAMS servers,
+ * we can still get the same problem. We will need a more sophisticated solution then.
+ */
+
+ synchronized (qbService) {
+ optionUid = qbService.allocateVSAnswerToOption(toolQuestionUid, targetOptionUid, previousOptionUid,
+ answer);
+ }
+
+ // recalculate marks for all lessons in all cases except for reshuffling inside the same container
+ answerFoundInResults = toolService.recalculateMarksForVsaQuestion(toolQuestionUid, answer);
+ }
+
+ ObjectNode responseJSON = JsonNodeFactory.instance.objectNode();
+ responseJSON.put("isAnswerDuplicated", optionUid != null);
+ responseJSON.put("optionUid", optionUid == null ? -1 : optionUid);
+ responseJSON.put("answerFoundInResults", answerFoundInResults);
+ response.setContentType("application/json;charset=utf-8");
+ return responseJSON.toString();
+ }
+
+}
Index: lams_central/web/includes/javascript/vsaAllocate.js
===================================================================
diff -u -rd99e586940f6f2ca7a230ed6770dc51803d71e23 -r3085af1c7e3e6c3496af23a748d998886d7168fd
--- lams_central/web/includes/javascript/vsaAllocate.js (.../vsaAllocate.js) (revision d99e586940f6f2ca7a230ed6770dc51803d71e23)
+++ lams_central/web/includes/javascript/vsaAllocate.js (.../vsaAllocate.js) (revision 3085af1c7e3e6c3496af23a748d998886d7168fd)
@@ -10,15 +10,15 @@
filter: '.filtered', // 'filtered' class is not draggable
onEnd: function (evt) {
let data = {
- questionUid: questionUid,
+ toolQuestionUid: questionUid,
targetOptionUid: $(evt.to).data("option-uid"),
previousOptionUid: $(evt.from).data("option-uid"),
answer: $('.answer-text', evt.item).text()
};
data[csrfTokenName] = csrfTokenValue;
$.ajax({
- url: WEB_APP_URL + 'monitoring/allocateUserAnswer.do',
+ url: LAMS_URL + 'qb/vsa/allocateUserAnswer.do',
data: data,
method: 'post',
dataType: "json",
@@ -44,7 +44,7 @@
optionUid = container.data('option-uid'),
isCorrect = container.data('option-correct'),
data = {
- questionUid: questionUid,
+ toolQuestionUid: questionUid,
targetOptionUid: -1,
previousOptionUid: optionUid,
answer: answer
@@ -57,7 +57,7 @@
data[csrfTokenName] = csrfTokenValue;
$.ajax({
- url: WEB_APP_URL + 'monitoring/allocateUserAnswer.do',
+ url: LAMS_URL + 'qb/vsa/allocateUserAnswer.do',
data: data,
method: 'post',
dataType: "json",
Index: lams_central/web/qb/vsa/vsaAllocate.jsp
===================================================================
diff -u -rd99e586940f6f2ca7a230ed6770dc51803d71e23 -r3085af1c7e3e6c3496af23a748d998886d7168fd
--- lams_central/web/qb/vsa/vsaAllocate.jsp (.../vsaAllocate.jsp) (revision d99e586940f6f2ca7a230ed6770dc51803d71e23)
+++ lams_central/web/qb/vsa/vsaAllocate.jsp (.../vsaAllocate.jsp) (revision 3085af1c7e3e6c3496af23a748d998886d7168fd)
@@ -1,15 +1,15 @@
<%@ include file="/common/taglibs.jsp"%>
+
- <%@ include file="/common/header.jsp"%>
-
-
+
+
+
+
+
+
-
+
@@ -53,9 +57,10 @@
-
-
- <%@ include file="parts/vsaQuestionAllocate.jsp"%>
+
+
+
+ <%@ include file="vsaQuestionAllocate.jsp"%>