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 dc25734a11c14cff29366843629aa1feb7d38387..2d713ea0357bed1007115e82b0b4eb68e78151ad 100644 --- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java +++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java @@ -461,7 +461,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen new ResourcesMapper(assessmentObjectUri, submissionDir)); resultCtrl = new AssessmentResultController(ureq, getWindowControl(), getIdentity(), true, session, - fUnzippedDirRoot, mapperUri, getDeliveryOptions().getAssessmentResultsOptions(), false, false); + fUnzippedDirRoot, mapperUri, null, getDeliveryOptions().getAssessmentResultsOptions(), false, false); listenTo(resultCtrl); mainVC.put("resultReport", resultCtrl.getInitialComponent()); mainVC.contextPut("showResults", Boolean.TRUE); diff --git a/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java b/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java index 5ea7081ad67a5e8b35eb384495cd84fd8da5c9d6..2f4f95745467cf5d3a67c44d06e6ae84efa16b5a 100644 --- a/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java +++ b/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java @@ -24,18 +24,15 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Set; import java.util.TimeZone; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -66,6 +63,7 @@ import org.olat.core.util.FileUtils; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.WebappHelper; +import org.olat.core.util.ZipUtil; import org.olat.course.nodes.QTICourseNode; import org.olat.course.run.environment.CourseEnvironment; import org.olat.fileresource.FileResourceManager; @@ -99,7 +97,8 @@ public class QTI21ResultsExportMediaResource implements MediaResource { private RepositoryEntry entry; private UserRequest ureq; - + + private final Set<RepositoryEntry> testEntries = new HashSet<>(); public QTI21ResultsExportMediaResource(CourseEnvironment courseEnv, List<Identity> identities, QTICourseNode courseNode, QTI21Service qtiService, UserRequest ureq) { @@ -110,6 +109,7 @@ public class QTI21ResultsExportMediaResource implements MediaResource { this.qtiService = qtiService; this.ureq = ureq; this.entry = courseEnv.getCourseGroupManager().getCourseEntry(); + translator = Util.createPackageTranslator(QTI21ResultsExportMediaResource.class, ureq.getLocale()); } public QTI21ResultsExportMediaResource(CourseEnvironment courseEnv, List<Identity> identities, QTICourseNode courseNode, @@ -153,7 +153,6 @@ public class QTI21ResultsExportMediaResource implements MediaResource { @Override public void prepare(HttpServletResponse hres) { //init package translator - translator = Util.createPackageTranslator(QTI21ResultsExportMediaResource.class, hres.getLocale()); exportFolderName = translator.translate("export.folder.name"); String label = StringHelper.transformDisplayNameToFileSystemName(title); @@ -168,27 +167,40 @@ public class QTI21ResultsExportMediaResource implements MediaResource { try { ZipOutputStream zout = new ZipOutputStream(hres.getOutputStream()); zout.setLevel(9); - - List<AssessedMember> assessedMembers = createAssessedMembersDetail(zout); - - //convert velocity template to zip entry - String membersHTML = createMemberListingHTML(assessedMembers); - convertToZipEntry(zout, exportFolderName + "/index.html", membersHTML); - - //Copy resource files or file trees to export file tree - File sasstheme = new File(WebappHelper.getContextRealPath("/static/offline/qti")); - fsToZip(zout, sasstheme.toPath(), exportFolderName + "/css/offline/qti/"); - - File fontawesome = new File(WebappHelper.getContextRealPath("/static/font-awesome")); - fsToZip(zout, fontawesome.toPath(), exportFolderName + "/css/font-awesome/"); - + exportTestResults(zout); zout.close(); - } catch (Exception e) { log.error("Unknown error while assessment result resource export", e); } } + /** + * Adds the result export to existing zip stream. + * + * @throws IOException + */ + public void exportTestResults(ZipOutputStream zout) throws IOException { + + List<AssessedMember> assessedMembers = createAssessedMembersDetail(zout); + + //convert velocity template to zip entry + String membersHTML = createMemberListingHTML(assessedMembers); + convertToZipEntry(zout, exportFolderName + "/index.html", membersHTML); + + //Copy resource files or file trees to export file tree + File sasstheme = new File(WebappHelper.getContextRealPath("/static/offline/qti")); + ZipUtil.addDirectoryToZip(sasstheme.toPath(), exportFolderName + "/css/offline/qti/", zout); + File fontawesome = new File(WebappHelper.getContextRealPath("/static/font-awesome")); + ZipUtil.addDirectoryToZip(fontawesome.toPath(), exportFolderName + "/css/font-awesome/", zout); + File qtiJs = new File(WebappHelper.getContextRealPath("/static/js/jquery/")); + ZipUtil.addDirectoryToZip(qtiJs.toPath(), exportFolderName + "/js/jquery/", zout); + + //materials + for(RepositoryEntry testEntry:testEntries) { + copyTestMaterials(testEntry, zout); + } + } + private List<ResultDetail> createResultDetail (Identity identity, ZipOutputStream zout, String idDir) throws IOException { List<ResultDetail> assessments = new ArrayList<ResultDetail>(); List<AssessmentTestSession> sessions = qtiService.getAssessmentTestSessions(entry, courseNode.getIdent(), identity); @@ -208,25 +220,32 @@ public class QTI21ResultsExportMediaResource implements MediaResource { WindowControl mockwControl = new WindowControlMocker(); FileResourceManager frm = FileResourceManager.getInstance(); - File fUnzippedDirRoot = frm.unzipFileResource(session.getTestEntry().getOlatResource()); + RepositoryEntry testEntry = session.getTestEntry(); + testEntries.add(testEntry); + File fUnzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource()); + String mapperUri = "../../../test" + testEntry.getKey() + "/";//add test repo key + String submissionMapperUri = "."; Controller assessmentResultController = new AssessmentResultController( ureq, mockwControl, identity, false, session, - fUnzippedDirRoot, null, QTI21AssessmentResultsOptions.allOptions(), false, true); + fUnzippedDirRoot, mapperUri, submissionMapperUri, QTI21AssessmentResultsOptions.allOptions(), false, true); Component component = assessmentResultController.getInitialComponent(); String componentHTML = createResultHTML(component); convertToZipEntry(zout, idPath + assessmentID +".html", componentHTML); File resultXML = qtiService.getAssessmentResultFile(session); - convertToZipEntry(zout, idPath + assessmentID +".xml", resultXML); + convertToZipEntry(zout, idPath + assessmentID +".xml", resultXML); + File submissionDir = qtiService.getSubmissionDirectory(session); + String baseDir = idPath + "submissions/"; + ZipUtil.addDirectoryToZip(submissionDir.toPath(), baseDir, zout); } return assessments; } private List<AssessedMember> createAssessedMembersDetail (ZipOutputStream zout) throws IOException { - List<AssessedMember> assessedMembers = new ArrayList<AssessedMember>(); + List<AssessedMember> assessedMembers = new ArrayList<>(); for (Identity identity : identities) { String idDir = exportFolderName + "/" + DATA + identity.getName(); @@ -258,27 +277,13 @@ public class QTI21ResultsExportMediaResource implements MediaResource { } return assessedMembers; } - - /** - * Adds the result export to existing zip stream. - * - * @throws IOException - */ - public void exportTestResults (ZipOutputStream zout) throws IOException { - - List<AssessedMember> assessedMembers = createAssessedMembersDetail(zout); - - //convert velocity template to zip entry - String membersHTML = createMemberListingHTML(assessedMembers); - convertToZipEntry(zout, exportFolderName + "/index.html", membersHTML); + private void copyTestMaterials(RepositoryEntry testEntry, ZipOutputStream zout) { + FileResourceManager frm = FileResourceManager.getInstance(); + File fUnzippedDirRoot = frm.unzipFileResource(testEntry.getOlatResource()); + String baseDir = exportFolderName + "/test" + testEntry.getKey(); + ZipUtil.addDirectoryToZip(fUnzippedDirRoot.toPath(), baseDir, zout); - //Copy resource files or file trees to export file tree - File sasstheme = new File(WebappHelper.getContextRealPath("/static/offline/qti")); - fsToZip(zout, sasstheme.toPath(), exportFolderName + "/css/offline/qti/"); - - File fontawesome = new File(WebappHelper.getContextRealPath("/static/font-awesome")); - fsToZip(zout, fontawesome.toPath(), exportFolderName + "/css/font-awesome/"); } private String createLink(String name, String href, boolean userview) { @@ -286,7 +291,6 @@ public class QTI21ResultsExportMediaResource implements MediaResource { return "<a href='" + href + "' target='" + targetLink + "' class='userLink'>" + name + "</a>"; } - private String createPassedIcons(boolean passed) { String icon = passed ? "<i class='o_icon o_passed o_icon_passed text-success'></i>" : "<i class='o_icon o_failed o_icon_failed text-danger'></i>"; @@ -302,25 +306,13 @@ public class QTI21ResultsExportMediaResource implements MediaResource { mainVC.contextPut("rootTitle", translator.translate("table.grading")); mainVC.put("results", results); - GlobalSettings globalSettings = new GlobalSettings() { - public int getFontSize() { return 100;} - public AJAXFlags getAjaxFlags() { return new EmptyAJAXFlags();} - public boolean isIdDivsForced() { return false; } - }; + //render VelocityContainer to StringOutPut - Renderer renderer = Renderer.getInstance(mainVC, translator, ubu, new RenderResult(), globalSettings); + Renderer renderer = Renderer.getInstance(mainVC, translator, ubu, new RenderResult(), new EmptyGlobalSettings()); renderer.render(sb, mainVC, null); - //mainVC.getHTMLRendererSingleton().render(renderer, sb, mainVC, ubu, tlr, new RenderResult(), null); - return sb.toString(); } - private static class EmptyAJAXFlags extends AJAXFlags { - public EmptyAJAXFlags() { super(null); } - @Override - public boolean isIframePostEnabled() { return false; } - } - private String createResultListingHTML (List<ResultDetail> assessments,AssessedMember assessedMember){ // now put values to velocityContext VelocityContext ctx = new VelocityContext(); @@ -356,26 +348,6 @@ public class QTI21ResultsExportMediaResource implements MediaResource { return velocityHelper.evaluateVTL(template, ctx); } - - private void fsToZip(ZipOutputStream zout, final Path sourceFolder, final String targetPath) throws IOException { - Files.walkFileTree(sourceFolder, new SimpleFileVisitor<Path>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - zout.putNextEntry(new ZipEntry(targetPath + sourceFolder.relativize(file).toString())); - Files.copy(file, zout); - zout.closeEntry(); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - zout.putNextEntry(new ZipEntry(targetPath + sourceFolder.relativize(dir).toString() + "/")); - zout.closeEntry(); - return FileVisitResult.CONTINUE; - } - }); - } - private void convertToZipEntry(ZipOutputStream zout, String link, File file) throws IOException { zout.putNextEntry(new ZipEntry(link)); try (InputStream in = new FileInputStream(file)) { @@ -404,10 +376,37 @@ public class QTI21ResultsExportMediaResource implements MediaResource { zout.closeEntry(); } - @Override public void release() { - + // } + private static class EmptyAJAXFlags extends AJAXFlags { + + public EmptyAJAXFlags() { + super(null); + } + + @Override + public boolean isIframePostEnabled() { + return false; + } + } + + private static class EmptyGlobalSettings implements GlobalSettings { + @Override + public int getFontSize() { + return 100; + } + + @Override + public AJAXFlags getAjaxFlags() { + return new EmptyAJAXFlags(); + } + + @Override + public boolean isIdDivsForced() { + return false; + } + }; } diff --git a/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html b/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html index f5e4a281298bfac2c905695642a6d5b282994e63..90fa8303e96abecc19a1a85d92e86072b0c4cc1f 100644 --- a/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html +++ b/src/main/java/org/olat/ims/qti21/resultexport/_content/qti21results.html @@ -3,7 +3,28 @@ <head> <title>$rootTitle</title> <link rel='stylesheet' href='../../../css/offline/qti/theme.css' /> + <script type="text/javascript" src='../../../js/jquery/jquery-2.1.3.min.js'></script> + <script type="text/javascript" src='../../../js/jquery/maphilight/jquery.maphilight.min.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.associate.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.gapMatch.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.graphicAssociate.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.graphicGap.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.graphicOrder.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.hotspot.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.match.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.order.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.positionObject.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.qtiTimer.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.selectPoint.js'></script> + <script type="text/javascript" src='../../../js/jquery/qti/jquery.slider.js'></script> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> + <script type="text/javascript"> +/* <![CDATA[ */ +function setFlexiFormDirtyByListener(e){ + // +} +/* ]]> */ + </script> </head> <body class="o_page_margins"> <div id="o_main">$r.render("results")</div> diff --git a/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java b/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java index 89e2070159d9fc53e2ecbec35b0f4005ac9038e5..fe3af2bf23f6cada0e841ebe37bc858e44756325 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java @@ -102,6 +102,7 @@ public class AssessmentResultController extends FormBasicController { private final String mapperUri; private String signatureMapperUri; + private final String submissionMapperUri; private final QTI21AssessmentResultsOptions options; private final boolean anonym; @@ -125,7 +126,7 @@ public class AssessmentResultController extends FormBasicController { private QTI21Service qtiService; public AssessmentResultController(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, boolean anonym, - AssessmentTestSession candidateSession, File fUnzippedDirRoot, String mapperUri, + AssessmentTestSession candidateSession, File fUnzippedDirRoot, String mapperUri, String submissionMapperUri, QTI21AssessmentResultsOptions options, boolean withPrint, boolean withTitle) { super(ureq, wControl, "assessment_results"); @@ -137,6 +138,7 @@ public class AssessmentResultController extends FormBasicController { this.assessedIdentity = assessedIdentity; this.candidateSession = candidateSession; this.fUnzippedDirRoot = fUnzippedDirRoot; + this.submissionMapperUri = submissionMapperUri; ResourceLocator fileResourceLocator = new PathResourceLocator(fUnzippedDirRoot.toPath()); inputResourceLocator = @@ -336,6 +338,9 @@ public class AssessmentResultController extends FormBasicController { formItem.setResourceLocator(inputResourceLocator); formItem.setAssessmentObjectUri(assessmentObjectUri); formItem.setMapperUri(mapperUri); + if(submissionMapperUri != null) { + formItem.setSubmissionMapperUri(submissionMapperUri); + } } private void extractOutcomeVariable(List<ItemVariable> itemVariables, Results results) { @@ -391,7 +396,7 @@ public class AssessmentResultController extends FormBasicController { @Override public Controller createController(UserRequest uureq, WindowControl wwControl) { AssessmentResultController printViewCtrl = new AssessmentResultController(uureq, wwControl, assessedIdentity, anonym, - candidateSession, fUnzippedDirRoot, mapperUri, options, false, true); + candidateSession, fUnzippedDirRoot, mapperUri, submissionMapperUri, options, false, true); printViewCtrl.flc.contextPut("printCommand", Boolean.TRUE); listenTo(printViewCtrl); return printViewCtrl; 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 436c46c161aca832ecf1ebf4851381299988c0c8..0dc9cbb14ff209454cb82069141733f2dfd335dc 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentTestDisplayController.java @@ -1819,7 +1819,7 @@ public class AssessmentTestDisplayController extends BasicController implements removeAsListenerAndDispose(resultCtrl); resultCtrl = new AssessmentResultController(ureq, getWindowControl(), assessedIdentity, anonym, AssessmentTestDisplayController.this.getCandidateSession(), - fUnzippedDirRoot, mapperUri, deliveryOptions.getAssessmentResultsOptions(), false, true); + fUnzippedDirRoot, mapperUri, null, deliveryOptions.getAssessmentResultsOptions(), false, true); listenTo(resultCtrl); flc.add("qtiResults", resultCtrl.getInitialFormItem()); resultsVisible = true; diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java index 5d47f62bb36144a17f9125bad2029434ee5f76be..5ca22b1212272add6231d051351d126f4d04f404 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java @@ -410,7 +410,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController { new ResourcesMapper(assessmentObjectUri, submissionDir)); resultCtrl = new AssessmentResultController(ureq, getWindowControl(), assessedIdentity, false, session, - fUnzippedDirRoot, mapperUri, QTI21AssessmentResultsOptions.allOptions(), true, true); + fUnzippedDirRoot, mapperUri, null, QTI21AssessmentResultsOptions.allOptions(), true, true); listenTo(resultCtrl); cmc = new CloseableModalController(getWindowControl(), "close", resultCtrl.getInitialComponent(), true, translate("table.header.results")); diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java index 82298ac3341479eca17ba1675bb34fbc7d47de7a..017781e1784d45091d619262411d9be94aa1c457 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectComponent.java @@ -54,6 +54,7 @@ public abstract class AssessmentObjectComponent extends AbstractComponent implem private Context context; private String mapperUri; + private String submissionMapperUri; private URI assessmentObjectUri; private ResourceLocator resourceLocator; private CandidateSessionContext candidateSessionContext; @@ -71,6 +72,19 @@ public abstract class AssessmentObjectComponent extends AbstractComponent implem public void setMapperUri(String mapperUri) { this.mapperUri = mapperUri; } + + /** + * Allow to define a specific mapper uri for the uploaded files. + * + * @return The specific submission mapper uri or the standard one if it was not defined + */ + public String getSubmissionMapperUri() { + return submissionMapperUri == null ? mapperUri : submissionMapperUri; + } + + public void setSubmissionMapperUri(String submissionMapperUri) { + this.submissionMapperUri = submissionMapperUri; + } public URI getAssessmentObjectUri() { return assessmentObjectUri; diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectFormItem.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectFormItem.java index b23bd7d1c38cd84d74ac910c9b052bc5a9003dd5..40e69b96d3abe17a3d6e452fb8023a7aada3ea1a 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectFormItem.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectFormItem.java @@ -83,6 +83,14 @@ public abstract class AssessmentObjectFormItem extends FormItemImpl implements F getComponent().setMapperUri(mapperUri); } + public String getSubmissionMapperUri() { + return getComponent().getSubmissionMapperUri(); + } + + public void setSubmissionMapperUri(String submissionMapperUri) { + getComponent().setSubmissionMapperUri(submissionMapperUri); + } + public URI getAssessmentObjectUri() { return getComponent().getAssessmentObjectUri(); } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java index a7c6d76e9e37cbd542ccbad89a7f2ba273058e55..1be51d263f5c45414e1c50c21b90a7bd49350c32 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentObjectVelocityRenderDecorator.java @@ -177,6 +177,10 @@ public class AssessmentObjectVelocityRenderDecorator extends VelocityRenderDecor return path.concat(url); } + public String convertSubmissionLinkFull(String uri) { + return AssessmentRenderFunctions.convertSubmissionLink(avc, resolvedAssessmentItem, uri); + } + public String getFormDispatchFieldId() { return avc.getQtiItem().getRootForm().getDispatchFieldId(); } diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java index 73f2feb99d88f5f6f604553f347e35ce7bd84f90..03cf91b81a1ab6f74f1dea8643250566537d972d 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentRenderFunctions.java @@ -617,11 +617,24 @@ public class AssessmentRenderFunctions { </xsl:choose> </xsl:function> */ + public static final String convertLink(AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, String uri) { if(uri != null && uri.startsWith("http:") || uri.startsWith("https:") || uri.startsWith("mailto:")) { return uri; } + String filename = getLinkFilename(uri); + String relativePath = component.relativePathTo(resolvedAssessmentItem); + return component.getMapperUri() + "/" + filename + "?href=" + relativePath + (uri == null ? "" : uri); + } + + public static final String convertSubmissionLink(AssessmentObjectComponent component, ResolvedAssessmentItem resolvedAssessmentItem, String uri) { + String filename = getLinkFilename(uri); + String relativePath = component.relativePathTo(resolvedAssessmentItem); + return component.getSubmissionMapperUri() + "/submissions/" + filename + "?href=" + relativePath + (uri == null ? "" : uri); + } + + private static final String getLinkFilename(String uri) { String filename = "file"; try { if(StringHelper.containsNonWhitespace(uri)) { @@ -635,9 +648,7 @@ public class AssessmentRenderFunctions { } catch (Exception e) { log.error("", e); } - - String relativePath = component.relativePathTo(resolvedAssessmentItem); - return component.getMapperUri() + "/" + filename + "?href=" + relativePath + (uri == null ? "" : uri); + return filename; } public static final boolean testFeedbackVisible(TestFeedback testFeedback, TestSessionState testSessionState) { diff --git a/src/main/java/org/olat/ims/qti21/ui/components/_content/uploadInteraction.html b/src/main/java/org/olat/ims/qti21/ui/components/_content/uploadInteraction.html index 3a3da86905f629e1c9667512bab1f6f949a78bcb..547e9ed01d976efe097524aee4295c1b2ac7666e 100644 --- a/src/main/java/org/olat/ims/qti21/ui/components/_content/uploadInteraction.html +++ b/src/main/java/org/olat/ims/qti21/ui/components/_content/uploadInteraction.html @@ -23,7 +23,7 @@ </div> </div> #else - <a href="${r.convertLinkFull("submissions/${r.getAssessmentTestSessionKey()}/$responseValue.fileName")}" target="_blank"><i class="o_icon $r.getFiletypeIconCss($responseValue.fileName)"> </i> $responseValue.fileName</a> + <a href='${r.convertSubmissionLinkFull("submissions/${r.getAssessmentTestSessionKey()}/$responseValue.fileName")}' target="_blank"><i class="o_icon $r.getFiletypeIconCss($responseValue.fileName)"> </i> $responseValue.fileName</a> #end #else ## Nothing uploaded yet