diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java index fc5be993b87b5984dd89db682d7f3dc3040bc35c..b6fc424ca34dff7c8fe1e857315c2c94e463f477 100644 --- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java +++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java @@ -570,8 +570,11 @@ public class QTI21AssessmentRunController extends BasicController implements Gen displayCtrl = new AssessmentTestDisplayController(ureq, bwControl, this, testEntry, courseRe, courseNode.getIdent(), deliveryOptions, overrideOptions, true, false, false); listenTo(displayCtrl); - if(displayCtrl.isTerminated()) { - //do nothing + if(displayCtrl.isEnded()) { + if(!displayCtrl.isResultsVisible()) { + doExitAssessment(ureq, null, true); + initAssessment(ureq); + } } else { // in case displayController was unable to initialize, a message was set by displayController // this is the case if no more attempts or security check was unsuccessfull @@ -638,7 +641,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen /** * Remove the runtime from the GUI stack only. * @param ureq - * @param event + * @param event The event which triggered the method (optional) * @param testEnded true if the test was ended and not suspended or cancelled (use to control increment of attempts) */ private void doExitAssessment(UserRequest ureq, Event event, boolean testEnded) { @@ -662,7 +665,9 @@ public class QTI21AssessmentRunController extends BasicController implements Gen incrementAttempts.set(true); } - fireEvent(ureq, event); + if(event != null) { + fireEvent(ureq, event); + } } @Override diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java index 54da0a8e8313f67acece9db3b113b6e61e71ddc6..1d49aa9a32a03b0cd3148761f360bea51565ba9f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java @@ -258,11 +258,11 @@ public class AssessmentTestDisplayController extends BasicController implements /* Handle immediate end of test session */ if (testSessionController.getTestSessionState() != null && testSessionController.getTestSessionState().isEnded()) { - immediateEndTestSession(ureq); - mainVC = createVelocityContainer("end"); + immediateEndTestSession(ureq); + mainVC = createVelocityContainer("end"); } else { - mainVC = createVelocityContainer("run"); - initQtiWorks(ureq); + mainVC = createVelocityContainer("run"); + initQtiWorks(ureq); } OLATResourceable sessionOres = OresHelper @@ -378,11 +378,21 @@ public class AssessmentTestDisplayController extends BasicController implements .createOLATResourceableInstance(AssessmentTestSession.class, candidateSession.getKey()); CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, sessionOres); } - + + /** + * @return true if the termination time is set. + */ @Override public boolean isTerminated() { return candidateSession.getTerminationTime() != null; } + + /** + * @return true if the termination time or the finished time is set. + */ + public boolean isEnded() { + return candidateSession.getTerminationTime() != null || candidateSession.getFinishTime() != null; + } @Override public AssessmentTestSession getCandidateSession() { @@ -400,7 +410,7 @@ public class AssessmentTestDisplayController extends BasicController implements } public boolean isResultsVisible() { - return qtiWorksCtrl.isResultsVisible(); + return qtiWorksCtrl != null && qtiWorksCtrl.isResultsVisible(); } @Override @@ -840,7 +850,7 @@ public class AssessmentTestDisplayController extends BasicController implements /* If we ended the testPart and there are now no more available testParts, then finish the session now */ if (nextItemNode==null && testSessionController.findNextEnterableTestPart()==null) { - candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, + candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, requestTimestamp, getDigitalSignatureOptions(), getIdentity()); } @@ -1462,21 +1472,23 @@ public class AssessmentTestDisplayController extends BasicController implements final NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO); TestSessionController controller = createTestSessionController(notificationRecorder); - controller.unsuspendTestSession(requestTimestamp); - - TestSessionState testSessionState = controller.getTestSessionState(); - TestPlanNodeKey currentItemKey = testSessionState.getCurrentItemKey(); - if(currentItemKey != null) { - TestPlanNode currentItemNode = testSessionState.getTestPlan().getNode(currentItemKey); - ItemProcessingContext itemProcessingContext = controller.getItemProcessingContext(currentItemNode); - ItemSessionState itemSessionState = itemProcessingContext.getItemSessionState(); - if(itemProcessingContext instanceof ItemSessionController - && itemSessionState.isSuspended()) { - ItemSessionController itemSessionController = (ItemSessionController)itemProcessingContext; - itemSessionController.unsuspendItemSession(requestTimestamp); - } - } - + if(!controller.getTestSessionState().isEnded() && !controller.getTestSessionState().isExited()) { + controller.unsuspendTestSession(requestTimestamp); + + TestSessionState testSessionState = controller.getTestSessionState(); + TestPlanNodeKey currentItemKey = testSessionState.getCurrentItemKey(); + if(currentItemKey != null) { + TestPlanNode currentItemNode = testSessionState.getTestPlan().getNode(currentItemKey); + ItemProcessingContext itemProcessingContext = controller.getItemProcessingContext(currentItemNode); + ItemSessionState itemSessionState = itemProcessingContext.getItemSessionState(); + if(itemProcessingContext instanceof ItemSessionController + && itemSessionState.isSuspended()) { + ItemSessionController itemSessionController = (ItemSessionController)itemProcessingContext; + itemSessionController.unsuspendItemSession(requestTimestamp); + } + } + } + return controller; }