Search in sources :

Example 1 with CandidateSessionContext

use of org.olat.ims.qti21.ui.CandidateSessionContext in project OpenOLAT by OpenOLAT.

the class AssessmentTreeComponentRenderer method renderTestEvent.

private void renderTestEvent(TestSessionController testSessionController, AssessmentRenderer renderer, StringOutput target, AssessmentTreeComponent component, URLBuilder ubu, Translator translator, RenderingRequest options) {
    CandidateSessionContext candidateSessionContext = component.getCandidateSessionContext();
    CandidateEvent candidateEvent = candidateSessionContext.getLastEvent();
    CandidateTestEventType testEventType = candidateEvent.getTestEventType();
    final TestSessionState testSessionState = testSessionController.getTestSessionState();
    if (!candidateSessionContext.isTerminated() && !testSessionState.isExited()) {
        if (testEventType == CandidateTestEventType.REVIEW_ITEM) {
            renderer.setReviewMode(true);
        } else if (testEventType == CandidateTestEventType.SOLUTION_ITEM) {
            renderer.setSolutionMode(true);
        }
        renderNavigation(renderer, target, component, ubu, translator, options);
    }
}
Also used : CandidateSessionContext(org.olat.ims.qti21.ui.CandidateSessionContext) TestSessionState(uk.ac.ed.ph.jqtiplus.state.TestSessionState) CandidateTestEventType(org.olat.ims.qti21.model.audit.CandidateTestEventType) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent)

Example 2 with CandidateSessionContext

use of org.olat.ims.qti21.ui.CandidateSessionContext in project OpenOLAT by OpenOLAT.

the class AssessmentItemComponentRenderer method render.

@Override
public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator, RenderResult renderResult, String[] args) {
    AssessmentItemComponent cmp = (AssessmentItemComponent) source;
    sb.append("<div class='qtiworks o_assessmentitem'>");
    ItemSessionController itemSessionController = cmp.getItemSessionController();
    CandidateSessionContext candidateSessionContext = cmp.getCandidateSessionContext();
    /* Create appropriate options that link back to this controller */
    final AssessmentTestSession candidateSession = candidateSessionContext.getCandidateSession();
    if (candidateSession != null && candidateSession.isExploded()) {
        renderExploded(sb, translator);
    } else if (candidateSessionContext.isTerminated()) {
        renderTerminated(sb, translator);
    } else {
        /* Look up most recent event */
        // assertSessionEntered(candidateSession);
        final CandidateEvent latestEvent = candidateSessionContext.getLastEvent();
        /* Load the ItemSessionState */
        // candidateDataService.loadItemSessionState(latestEvent);
        final ItemSessionState itemSessionState = cmp.getItemSessionController().getItemSessionState();
        /* Touch the session's duration state if appropriate */
        if (itemSessionState.isEntered() && !itemSessionState.isEnded() && !itemSessionState.isSuspended()) {
            final Date timestamp = candidateSessionContext.getCurrentRequestTimestamp();
            itemSessionController.touchDuration(timestamp);
        }
        /* Render event */
        AssessmentRenderer renderHints = new AssessmentRenderer(renderer);
        renderItemEvent(renderHints, sb, cmp, latestEvent, itemSessionState, ubu, translator);
    }
    sb.append("</div>");
}
Also used : CandidateSessionContext(org.olat.ims.qti21.ui.CandidateSessionContext) AssessmentTestSession(org.olat.ims.qti21.AssessmentTestSession) ItemSessionState(uk.ac.ed.ph.jqtiplus.state.ItemSessionState) ItemSessionController(uk.ac.ed.ph.jqtiplus.running.ItemSessionController) Date(java.util.Date) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent)

Example 3 with CandidateSessionContext

use of org.olat.ims.qti21.ui.CandidateSessionContext in project openolat by klemens.

the class AssessmentTestDisplayController method processFinishLinearItem.

// public CandidateSession finishLinearItem(final CandidateSessionContext candidateSessionContext)
// throws CandidateException {
private void processFinishLinearItem(UserRequest ureq) {
    NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO);
    TestSessionState testSessionState = testSessionController.getTestSessionState();
    try {
        if (!testSessionController.mayAdvanceItemLinear()) {
            candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANNOT_FINISH_LINEAR_TEST_ITEM, null);
            logError("CANNOT_FINISH_LINEAR_TEST_ITEM", null);
            return;
        }
    } catch (RuntimeException e) {
        candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANNOT_FINISH_LINEAR_TEST_ITEM, e);
        logError("CANNOT_FINISH_LINEAR_TEST_ITEM", e);
        return;
    }
    // Update state
    final Date requestTimestamp = ureq.getRequestTimestamp();
    final TestPlanNode nextItemNode = testSessionController.advanceItemLinear(requestTimestamp);
    boolean terminated = nextItemNode == null && testSessionController.findNextEnterableTestPart() == null;
    // Record current result state
    final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(requestTimestamp, testSessionState, terminated);
    /* If we ended the testPart and there are now no more available testParts, then finish the session now */
    if (terminated) {
        candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, requestTimestamp, getDigitalSignatureOptions(), getIdentity());
    }
    // Record and log event
    final CandidateTestEventType eventType = nextItemNode != null ? CandidateTestEventType.FINISH_ITEM : CandidateTestEventType.FINISH_FINAL_ITEM;
    final CandidateEvent candidateTestEvent = qtiService.recordCandidateTestEvent(candidateSession, testEntry, entry, eventType, null, null, testSessionState, notificationRecorder);
    this.lastEvent = candidateTestEvent;
    candidateAuditLogger.logCandidateEvent(candidateTestEvent);
}
Also used : TestPlanNode(uk.ac.ed.ph.jqtiplus.state.TestPlanNode) OLATRuntimeException(org.olat.core.logging.OLATRuntimeException) TestSessionState(uk.ac.ed.ph.jqtiplus.state.TestSessionState) CandidateTestEventType(org.olat.ims.qti21.model.audit.CandidateTestEventType) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) AssessmentResult(uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult) Date(java.util.Date) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent)

Example 4 with CandidateSessionContext

use of org.olat.ims.qti21.ui.CandidateSessionContext in project openolat by klemens.

the class AssessmentTestDisplayController method processEndTestPart.

// public CandidateSession endCurrentTestPart(final CandidateSessionContext candidateSessionContext)
private void processEndTestPart(UserRequest ureq) {
    /* Update state */
    final Date requestTimestamp = ureq.getRequestTimestamp();
    testSessionController.endCurrentTestPart(requestTimestamp);
    TestSessionState testSessionState = testSessionController.getTestSessionState();
    TestPlanNode nextTestPart = testSessionController.findNextEnterableTestPart();
    // Record current result state
    final AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(requestTimestamp, testSessionState, nextTestPart == null);
    if (nextTestPart == null) {
        candidateSession = qtiService.finishTestSession(candidateSession, testSessionState, assessmentResult, requestTimestamp, getDigitalSignatureOptions(), getIdentity());
        if (!qtiWorksCtrl.willShowSomeAssessmentTestFeedbacks()) {
            // need feedback, no more parts, quickly exit
            try {
                // end current test part
                testSessionController.enterNextAvailableTestPart(requestTimestamp);
            } catch (final QtiCandidateStateException e) {
                candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANNOT_ADVANCE_TEST_PART, e);
                logError("CANNOT_ADVANCE_TEST_PART", e);
                return;
            } catch (final RuntimeException e) {
                candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANNOT_ADVANCE_TEST_PART, e);
                logError("RuntimeException", e);
                // handleExplosion(e, candidateSession);
                return;
            }
            // exit the test
            NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO);
            CandidateTestEventType eventType = CandidateTestEventType.EXIT_TEST;
            testSessionController.exitTest(requestTimestamp);
            candidateSession.setTerminationTime(requestTimestamp);
            candidateSession = qtiService.updateAssessmentTestSession(candidateSession);
            /* Record and log event */
            final CandidateEvent candidateTestEvent = qtiService.recordCandidateTestEvent(candidateSession, testEntry, entry, eventType, testSessionState, notificationRecorder);
            candidateAuditLogger.logCandidateEvent(candidateTestEvent);
            this.lastEvent = candidateTestEvent;
            qtiWorksCtrl.updateStatusAndResults(ureq);
            doExitTest(ureq);
        }
    } else if (!qtiWorksCtrl.willShowSomeTestPartFeedbacks()) {
        // no feedback, go to the next part
        processAdvanceTestPart(ureq);
    }
}
Also used : TestPlanNode(uk.ac.ed.ph.jqtiplus.state.TestPlanNode) QtiCandidateStateException(uk.ac.ed.ph.jqtiplus.exception.QtiCandidateStateException) OLATRuntimeException(org.olat.core.logging.OLATRuntimeException) TestSessionState(uk.ac.ed.ph.jqtiplus.state.TestSessionState) CandidateTestEventType(org.olat.ims.qti21.model.audit.CandidateTestEventType) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) AssessmentResult(uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult) Date(java.util.Date) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent)

Example 5 with CandidateSessionContext

use of org.olat.ims.qti21.ui.CandidateSessionContext in project openolat by klemens.

the class AssessmentTestDisplayController method handleResponse.

// public CandidateSession handleResponses(final CandidateSessionContext candidateSessionContext,
// final Map<Identifier, StringResponseData> stringResponseMap,
// final Map<Identifier, MultipartFile> fileResponseMap,
// final String candidateComment)
private void handleResponse(UserRequest ureq, Map<Identifier, ResponseInput> stringResponseMap, Map<Identifier, ResponseInput> fileResponseMap, String candidateComment) {
    NotificationRecorder notificationRecorder = new NotificationRecorder(NotificationLevel.INFO);
    TestSessionState testSessionState = testSessionController.getTestSessionState();
    TestPlanNodeKey currentItemKey = testSessionState.getCurrentItemKey();
    if (currentItemKey == null && getLastEvent() != null && getLastEvent().getTestEventType() == CandidateTestEventType.REVIEW_ITEM) {
        // someone try to send the form in review with tab / return
        return;
    }
    if (!qtiWorksCtrl.validatePresentedItem(currentItemKey)) {
        logError("Response send by browser doesn't match current item key", null);
        ServletUtil.printOutRequestParameters(ureq.getHttpReq());
        if (candidateSession != null && candidateSession.getFinishTime() != null) {
            showWarning("error.test.closed");
        } else {
            showWarning("error.reload.question");
        }
        // this is not the right node in the plan
        return;
    }
    final Map<Identifier, File> fileSubmissionMap = new HashMap<>();
    final Map<Identifier, ResponseData> responseDataMap = new HashMap<>();
    if (stringResponseMap != null) {
        for (final Entry<Identifier, ResponseInput> responseEntry : stringResponseMap.entrySet()) {
            final Identifier identifier = responseEntry.getKey();
            final ResponseInput responseData = responseEntry.getValue();
            if (responseData instanceof StringInput) {
                responseDataMap.put(identifier, new StringResponseData(((StringInput) responseData).getResponseData()));
            } else if (responseData instanceof Base64Input) {
                // only used from drawing interaction
                Base64Input fileInput = (Base64Input) responseData;
                String filename = "submitted_image.png";
                File storedFile = qtiService.importFileSubmission(candidateSession, filename, fileInput.getResponseData());
                responseDataMap.put(identifier, new FileResponseData(storedFile, fileInput.getContentType(), storedFile.getName()));
                fileSubmissionMap.put(identifier, storedFile);
            } else if (responseData instanceof FileInput) {
                FileInput fileInput = (FileInput) responseData;
                File storedFile = qtiService.importFileSubmission(candidateSession, fileInput.getMultipartFileInfos());
                responseDataMap.put(identifier, new FileResponseData(storedFile, fileInput.getContentType(), storedFile.getName()));
                fileSubmissionMap.put(identifier, storedFile);
            }
        }
    }
    ParentPartItemRefs parentParts = getParentSection(currentItemKey);
    String assessmentItemIdentifier = currentItemKey.getIdentifier().toString();
    AssessmentItemSession itemSession = qtiService.getOrCreateAssessmentItemSession(candidateSession, parentParts, assessmentItemIdentifier);
    if (fileResponseMap != null) {
        for (Entry<Identifier, ResponseInput> fileResponseEntry : fileResponseMap.entrySet()) {
            Identifier identifier = fileResponseEntry.getKey();
            FileInput multipartFile = (FileInput) fileResponseEntry.getValue();
            if (!multipartFile.isEmpty()) {
                File storedFile = qtiService.importFileSubmission(candidateSession, multipartFile.getMultipartFileInfos());
                responseDataMap.put(identifier, new FileResponseData(storedFile, multipartFile.getContentType(), storedFile.getName()));
                fileSubmissionMap.put(identifier, storedFile);
            }
        }
    }
    Map<Identifier, AssessmentResponse> candidateResponseMap = qtiService.getAssessmentResponses(itemSession);
    for (Entry<Identifier, ResponseData> responseEntry : responseDataMap.entrySet()) {
        Identifier responseIdentifier = responseEntry.getKey();
        ResponseData responseData = responseEntry.getValue();
        AssessmentResponse candidateItemResponse;
        if (candidateResponseMap.containsKey(responseIdentifier)) {
            candidateItemResponse = candidateResponseMap.get(responseIdentifier);
        } else {
            candidateItemResponse = qtiService.createAssessmentResponse(candidateSession, itemSession, responseIdentifier.toString(), ResponseLegality.VALID, responseData.getType());
        }
        switch(responseData.getType()) {
            case STRING:
                {
                    List<String> data = ((StringResponseData) responseData).getResponseData();
                    String stringuifiedResponse = ResponseFormater.format(data);
                    candidateItemResponse.setStringuifiedResponse(stringuifiedResponse);
                    break;
                }
            case FILE:
                {
                    if (fileSubmissionMap.get(responseIdentifier) != null) {
                        File storedFile = fileSubmissionMap.get(responseIdentifier);
                        candidateItemResponse.setStringuifiedResponse(storedFile.getName());
                    }
                    break;
                }
            default:
                throw new OLATRuntimeException("Unexpected switch case: " + responseData.getType());
        }
        candidateResponseMap.put(responseIdentifier, candidateItemResponse);
    }
    boolean allResponsesValid = true;
    boolean allResponsesBound = true;
    final Date timestamp = ureq.getRequestTimestamp();
    if (candidateComment != null) {
        testSessionController.setCandidateCommentForCurrentItem(timestamp, candidateComment);
    }
    /* Attempt to bind responses (and maybe perform RP & OP) */
    testSessionController.handleResponsesToCurrentItem(timestamp, responseDataMap);
    /* Classify this event */
    final SubmissionMode submissionMode = testSessionController.getCurrentTestPart().getSubmissionMode();
    final CandidateItemEventType candidateItemEventType;
    if (allResponsesValid) {
        candidateItemEventType = submissionMode == SubmissionMode.INDIVIDUAL ? CandidateItemEventType.ATTEMPT_VALID : CandidateItemEventType.RESPONSE_VALID;
    } else {
        candidateItemEventType = allResponsesBound ? CandidateItemEventType.RESPONSE_INVALID : CandidateItemEventType.RESPONSE_BAD;
    }
    /* Record resulting event */
    final CandidateEvent candidateEvent = qtiService.recordCandidateTestEvent(candidateSession, testEntry, entry, CandidateTestEventType.ITEM_EVENT, candidateItemEventType, currentItemKey, testSessionState, notificationRecorder);
    candidateAuditLogger.logCandidateEvent(candidateEvent, candidateResponseMap);
    this.lastEvent = candidateEvent;
    /* Record current result state */
    AssessmentResult assessmentResult = computeAndRecordTestAssessmentResult(timestamp, testSessionState, false);
    ItemSessionState itemSessionState = testSessionState.getCurrentItemSessionState();
    long itemDuration = itemSessionState.getDurationAccumulated();
    itemSession.setDuration(itemDuration);
    ItemResult itemResult = assessmentResult.getItemResult(assessmentItemIdentifier);
    collectOutcomeVariablesForItemSession(itemResult, itemSession);
    /* Persist CandidateResponse entities */
    qtiService.recordTestAssessmentResponses(itemSession, candidateResponseMap.values());
    /* Save any change to session state */
    candidateSession = qtiService.updateAssessmentTestSession(candidateSession);
    addToHistory(ureq, this);
    checkConcurrentExit(ureq);
}
Also used : TestSessionState(uk.ac.ed.ph.jqtiplus.state.TestSessionState) HashMap(java.util.HashMap) FileInput(org.olat.ims.qti21.ui.ResponseInput.FileInput) CandidateEvent(org.olat.ims.qti21.model.audit.CandidateEvent) Identifier(uk.ac.ed.ph.jqtiplus.types.Identifier) SubmissionMode(uk.ac.ed.ph.jqtiplus.node.test.SubmissionMode) StringResponseData(uk.ac.ed.ph.jqtiplus.types.StringResponseData) AssessmentItemSession(org.olat.ims.qti21.AssessmentItemSession) List(java.util.List) AssessmentResult(uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult) ParentPartItemRefs(org.olat.ims.qti21.model.ParentPartItemRefs) CandidateItemEventType(org.olat.ims.qti21.model.audit.CandidateItemEventType) FileResponseData(uk.ac.ed.ph.jqtiplus.types.FileResponseData) StringResponseData(uk.ac.ed.ph.jqtiplus.types.StringResponseData) ResponseData(uk.ac.ed.ph.jqtiplus.types.ResponseData) ItemSessionState(uk.ac.ed.ph.jqtiplus.state.ItemSessionState) NotificationRecorder(uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder) AssessmentResponse(org.olat.ims.qti21.AssessmentResponse) Date(java.util.Date) StringInput(org.olat.ims.qti21.ui.ResponseInput.StringInput) ItemResult(uk.ac.ed.ph.jqtiplus.node.result.ItemResult) OLATRuntimeException(org.olat.core.logging.OLATRuntimeException) FileResponseData(uk.ac.ed.ph.jqtiplus.types.FileResponseData) Base64Input(org.olat.ims.qti21.ui.ResponseInput.Base64Input) File(java.io.File) TestPlanNodeKey(uk.ac.ed.ph.jqtiplus.state.TestPlanNodeKey)

Aggregations

CandidateEvent (org.olat.ims.qti21.model.audit.CandidateEvent)14 TestSessionState (uk.ac.ed.ph.jqtiplus.state.TestSessionState)12 Date (java.util.Date)10 CandidateTestEventType (org.olat.ims.qti21.model.audit.CandidateTestEventType)10 CandidateSessionContext (org.olat.ims.qti21.ui.CandidateSessionContext)10 OLATRuntimeException (org.olat.core.logging.OLATRuntimeException)6 AssessmentTestSession (org.olat.ims.qti21.AssessmentTestSession)6 AssessmentResult (uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult)6 NotificationRecorder (uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder)6 TestSessionController (uk.ac.ed.ph.jqtiplus.running.TestSessionController)4 ItemSessionState (uk.ac.ed.ph.jqtiplus.state.ItemSessionState)4 TestPlanNode (uk.ac.ed.ph.jqtiplus.state.TestPlanNode)4 TestPlanNodeKey (uk.ac.ed.ph.jqtiplus.state.TestPlanNodeKey)4 QtiCandidateStateException (uk.ac.ed.ph.jqtiplus.exception.QtiCandidateStateException)3 File (java.io.File)2 HashMap (java.util.HashMap)2 List (java.util.List)2 AssessmentItemSession (org.olat.ims.qti21.AssessmentItemSession)2 AssessmentResponse (org.olat.ims.qti21.AssessmentResponse)2 ParentPartItemRefs (org.olat.ims.qti21.model.ParentPartItemRefs)2