Search in sources :

Example 21 with AssessmentResult

use of uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult in project OpenOLAT by OpenOLAT.

the class AssessmentItemDisplayController method updateSessionFinishedStatus.

private AssessmentTestSession updateSessionFinishedStatus(UserRequest ureq) {
    /* Record current result state and maybe close session */
    final ItemSessionState itemSessionState = itemSessionController.getItemSessionState();
    final AssessmentResult assessmentResult = computeAndRecordItemAssessmentResult(ureq);
    if (itemSessionState.isEnded()) {
        qtiService.finishItemSession(candidateSession, assessmentResult, null);
    } else {
        if (candidateSession != null && candidateSession.getFinishTime() != null) {
            /* (Session is being reopened) */
            candidateSession.setFinishTime(null);
            candidateSession = qtiService.updateAssessmentTestSession(candidateSession);
        }
    }
    return candidateSession;
}
Also used : ItemSessionState(uk.ac.ed.ph.jqtiplus.state.ItemSessionState) AssessmentResult(uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult)

Example 22 with AssessmentResult

use of uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult in project OpenOLAT by OpenOLAT.

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 23 with AssessmentResult

use of uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult in project OpenOLAT by OpenOLAT.

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)

Example 24 with AssessmentResult

use of uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult in project OpenOLAT by OpenOLAT.

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 (QtiCandidateStateException e) {
        candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANNOT_FINISH_LINEAR_TEST_ITEM, e);
        logError("CANNOT_FINISH_LINEAR_TEST_ITEM", e);
        return;
    } catch (RuntimeException e) {
        candidateAuditLogger.logAndThrowCandidateException(candidateSession, CandidateExceptionReason.CANNOT_FINISH_LINEAR_TEST_ITEM, e);
        logError("CANNOT_FINISH_LINEAR_TEST_ITEM", e);
        // handleExplosion(e, candidateSession);
        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, false);
    /* 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, 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) 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 25 with AssessmentResult

use of uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult in project openolat by klemens.

the class QTI21ServiceImpl method getAssessmentResult.

@Override
public AssessmentResult getAssessmentResult(AssessmentTestSession candidateSession) {
    File assessmentResultFile = getAssessmentResultFile(candidateSession);
    ResourceLocator fileResourceLocator = new PathResourceLocator(assessmentResultFile.getParentFile().toPath());
    ResourceLocator inputResourceLocator = ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator);
    URI assessmentResultUri = assessmentResultFile.toURI();
    QtiObjectReader qtiObjectReader = qtiXmlReader().createQtiObjectReader(inputResourceLocator, false, false);
    try {
        QtiObjectReadResult<AssessmentResult> result = qtiObjectReader.lookupRootNode(assessmentResultUri, AssessmentResult.class);
        return result.getRootNode();
    } catch (XmlResourceNotFoundException | QtiXmlInterpretationException | ClassCastException e) {
        log.error("", e);
        return null;
    }
}
Also used : ClassPathResourceLocator(uk.ac.ed.ph.jqtiplus.xmlutils.locators.ClassPathResourceLocator) PathResourceLocator(org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator) XmlResourceNotFoundException(uk.ac.ed.ph.jqtiplus.xmlutils.XmlResourceNotFoundException) QtiXmlInterpretationException(uk.ac.ed.ph.jqtiplus.reading.QtiXmlInterpretationException) QtiObjectReader(uk.ac.ed.ph.jqtiplus.reading.QtiObjectReader) File(java.io.File) URI(java.net.URI) AssessmentResult(uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult) ClassPathResourceLocator(uk.ac.ed.ph.jqtiplus.xmlutils.locators.ClassPathResourceLocator) ResourceLocator(uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator) PathResourceLocator(org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator)

Aggregations

AssessmentResult (uk.ac.ed.ph.jqtiplus.node.result.AssessmentResult)30 Date (java.util.Date)20 CandidateEvent (org.olat.ims.qti21.model.audit.CandidateEvent)20 NotificationRecorder (uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder)16 ItemSessionState (uk.ac.ed.ph.jqtiplus.state.ItemSessionState)14 TestSessionState (uk.ac.ed.ph.jqtiplus.state.TestSessionState)12 OLATRuntimeException (org.olat.core.logging.OLATRuntimeException)10 QtiCandidateStateException (uk.ac.ed.ph.jqtiplus.exception.QtiCandidateStateException)7 TestPlanNode (uk.ac.ed.ph.jqtiplus.state.TestPlanNode)6 File (java.io.File)4 HashMap (java.util.HashMap)4 List (java.util.List)4 AssessmentItemSession (org.olat.ims.qti21.AssessmentItemSession)4 AssessmentResponse (org.olat.ims.qti21.AssessmentResponse)4 ParentPartItemRefs (org.olat.ims.qti21.model.ParentPartItemRefs)4 CandidateTestEventType (org.olat.ims.qti21.model.audit.CandidateTestEventType)4 StringInput (org.olat.ims.qti21.ui.ResponseInput.StringInput)4 TestPlanNodeKey (uk.ac.ed.ph.jqtiplus.state.TestPlanNodeKey)4 FileResponseData (uk.ac.ed.ph.jqtiplus.types.FileResponseData)4 Identifier (uk.ac.ed.ph.jqtiplus.types.Identifier)4