diff --git a/src/main/java/org/olat/ims/qti21/ui/ResourcesMapper.java b/src/main/java/org/olat/ims/qti21/ui/ResourcesMapper.java index 4f0b1dda6aaa6bc72e6a92a9dd5b5bcd7f0baed5..a5688fa896e9f5176d3d7b6301c10cbc3fb7f5aa 100644 --- a/src/main/java/org/olat/ims/qti21/ui/ResourcesMapper.java +++ b/src/main/java/org/olat/ims/qti21/ui/ResourcesMapper.java @@ -48,6 +48,12 @@ public class ResourcesMapper implements Mapper { private final File submissionDirectory; private final Map<Long,File> submissionDirectoryMaps; + public ResourcesMapper(URI assessmentObjectUri) { + this.assessmentObjectUri = assessmentObjectUri; + submissionDirectory = null; + submissionDirectoryMaps = null; + } + public ResourcesMapper(URI assessmentObjectUri, File submissionDirectory) { this.assessmentObjectUri = assessmentObjectUri; this.submissionDirectory = submissionDirectory; diff --git a/src/main/java/org/olat/ims/qti21/ui/components/ItemBodyResultComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/ItemBodyResultComponent.java index 47b3c7f886fdaf439a83b9bc7b05f997ae7a7b94..5196b4dce23740362027fc85299f5d025a4b0670 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/ItemBodyResultComponent.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/ItemBodyResultComponent.java @@ -110,10 +110,15 @@ public class ItemBodyResultComponent extends AssessmentObjectComponent { public String relativePathTo(ResolvedAssessmentItem rAssessmentItem) { URI itemUri = rAssessmentItem.getItemLookup().getSystemId(); File itemFile = new File(itemUri); - URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId(); - File testFile = new File(testUri); - Path relativePath = testFile.toPath().getParent().relativize(itemFile.toPath().getParent()); - String relativePathString = relativePath.toString(); + + String relativePathString = ""; + if(resolvedAssessmentTest != null) { + URI testUri = resolvedAssessmentTest.getTestLookup().getSystemId(); + File testFile = new File(testUri); + Path relativePath = testFile.toPath().getParent().relativize(itemFile.toPath().getParent()); + relativePathString = relativePath.toString(); + } + if(relativePathString.isEmpty()) { return relativePathString; } else if(relativePathString.endsWith("/")) { diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java index 943222bc9e984cb7c4669de010016c57453220b6..638b2a0560c411c657b49a54384c09cb39008170 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/AssessmentItemEditorController.java @@ -219,7 +219,7 @@ public class AssessmentItemEditorController extends BasicController { } private void initItemCreatedByUnkownEditor(UserRequest ureq, AssessmentItem item) { - itemEditor = new UnkownItemEditorController(ureq, getWindowControl(), item); + itemEditor = new UnkownItemEditorController(ureq, getWindowControl(), resolvedAssessmentItem, item, rootDirectory); listenTo(itemEditor); tabbedPane.addTab(translate("form.unkown"), itemEditor); } diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java index 6050d5f0b48ec6652074fbdfaee94304360674a0..4994c459133883c8854f35753cb705f41c4951d6 100644 --- a/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java +++ b/src/main/java/org/olat/ims/qti21/ui/editor/UnkownItemEditorController.java @@ -19,25 +19,37 @@ */ package org.olat.ims.qti21.ui.editor; -import java.util.List; - -import javax.xml.transform.stream.StreamResult; +import java.io.File; +import java.net.URI; +import java.util.Date; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; -import org.olat.core.gui.render.StringOutput; +import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; +import org.olat.fileresource.types.ImsQTI21Resource; +import org.olat.fileresource.types.ImsQTI21Resource.PathResourceLocator; import org.olat.ims.qti21.QTI21Service; +import org.olat.ims.qti21.model.InMemoryAssessmentTestSession; +import org.olat.ims.qti21.ui.ResourcesMapper; +import org.olat.ims.qti21.ui.assessment.TerminatedStaticCandidateSessionContext; +import org.olat.ims.qti21.ui.components.ItemBodyResultFormItem; import org.springframework.beans.factory.annotation.Autowired; -import uk.ac.ed.ph.jqtiplus.node.content.basic.Block; import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem; -import uk.ac.ed.ph.jqtiplus.node.item.interaction.Interaction; -import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; +import uk.ac.ed.ph.jqtiplus.notification.NotificationLevel; +import uk.ac.ed.ph.jqtiplus.notification.NotificationRecorder; +import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem; +import uk.ac.ed.ph.jqtiplus.running.ItemProcessingInitializer; +import uk.ac.ed.ph.jqtiplus.running.ItemSessionController; +import uk.ac.ed.ph.jqtiplus.running.ItemSessionControllerSettings; +import uk.ac.ed.ph.jqtiplus.state.ItemProcessingMap; +import uk.ac.ed.ph.jqtiplus.state.ItemSessionState; +import uk.ac.ed.ph.jqtiplus.xmlutils.locators.ResourceLocator; /** * @@ -47,17 +59,33 @@ import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer; */ public class UnkownItemEditorController extends FormBasicController { + private final String mapperUri; private final AssessmentItem item; - private final QtiSerializer qtiSerializer; + private final URI assessmentObjectUri; + private final ResourceLocator inputResourceLocator; + private final ResolvedAssessmentItem resolvedAssessmentItem; + + private final ItemSessionController itemSessionController; @Autowired private QTI21Service qtiService; - public UnkownItemEditorController(UserRequest ureq, WindowControl wControl, AssessmentItem item) { + public UnkownItemEditorController(UserRequest ureq, WindowControl wControl, + ResolvedAssessmentItem resolvedAssessmentItem, AssessmentItem item, File fUnzippedDirRoot) { super(ureq, wControl); setTranslator(Util.createPackageTranslator(AssessmentTestEditorController.class, getLocale())); this.item = item; - qtiSerializer = qtiService.qtiSerializer(); + this.resolvedAssessmentItem = resolvedAssessmentItem; + + itemSessionController = createNewItemSessionStateAndController(); + + ResourceLocator fileResourceLocator = new PathResourceLocator(fUnzippedDirRoot.toPath()); + inputResourceLocator = + ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator); + assessmentObjectUri = qtiService.createAssessmentObjectUri(fUnzippedDirRoot); + + mapperUri = registerCacheableMapper(null, "QTI21AlienElement::" + CodeHelper.getRAMUniqueID(), + new ResourcesMapper(assessmentObjectUri)); initForm(ureq); } @@ -69,21 +97,37 @@ public class UnkownItemEditorController extends FormBasicController { String title = StringHelper.escapeHtml(item.getTitle()); uifactory.addStaticTextElement("title", "form.imd.title", title, formLayout); - //question - StringOutput sb = new StringOutput(); - List<Block> blocks = item.getItemBody().getBlocks(); - for(Block block:blocks) { - if(block instanceof Interaction) { - break; - } else if(block != null) { - qtiSerializer.serializeJqtiObject(block, new StreamResult(sb)); - } - } - - if(sb.length() > 0) { - uifactory.addStaticTextElement("desc", "form.imd.descr", sb.toString(), formLayout); - } + String responseId = "responseBody" + CodeHelper.getRAMUniqueID(); + ItemBodyResultFormItem formItem = new ItemBodyResultFormItem(responseId, resolvedAssessmentItem); + formLayout.add(responseId, formItem); + formItem.setLabel("form.imd.descr", null); + + formItem.setItemSessionState(itemSessionController.getItemSessionState()); + formItem.setCandidateSessionContext(new TerminatedStaticCandidateSessionContext(new InMemoryAssessmentTestSession())); + formItem.setResourceLocator(inputResourceLocator); + formItem.setAssessmentObjectUri(assessmentObjectUri); + formItem.setMapperUri(mapperUri); } + + private ItemSessionController createNewItemSessionStateAndController() { + /* Resolve the underlying JQTI+ object */ + final ItemProcessingMap itemProcessingMap = new ItemProcessingInitializer(resolvedAssessmentItem, true).initialize(); + + /* Create fresh state for session */ + final ItemSessionState itemSessionState = new ItemSessionState(); + final ItemSessionControllerSettings itemSessionControllerSettings = new ItemSessionControllerSettings(); + itemSessionControllerSettings.setTemplateProcessingLimit(25); + itemSessionControllerSettings.setMaxAttempts(10); + + /* Create controller and wire up notification recorder */ + final ItemSessionController itemSessionController = new ItemSessionController(qtiService.jqtiExtensionManager(), + itemSessionControllerSettings, itemProcessingMap, itemSessionState); + itemSessionController.addNotificationListener(new NotificationRecorder(NotificationLevel.ERROR)); + + + itemSessionController.initialize(new Date()); + return itemSessionController; + } @Override protected void doDispose() {