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 b8304c63d23a39bcb81c45a8e21c4d0811c4c79a..d407bc46737e5d1b8034eef90baac7c8b4f0afdf 100644 --- a/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java +++ b/src/main/java/org/olat/ims/qti21/ui/AssessmentResultController.java @@ -115,16 +115,17 @@ public class AssessmentResultController extends FormBasicController { private String signatureMapperUri; private final String submissionMapperUri; private final QTI21AssessmentResultsOptions options; + private boolean testSessionError = false; private final boolean anonym; private final boolean withPrint; private final boolean withTitle; private final boolean toggleSolution; private final Identity assessedIdentity; - private final TestSessionState testSessionState; - private final AssessmentResult assessmentResult; - private final AssessmentTestSession candidateSession; - private final CandidateSessionContext candidateSessionContext; + private TestSessionState testSessionState; + private AssessmentResult assessmentResult; + private AssessmentTestSession candidateSession; + private CandidateSessionContext candidateSessionContext; private final File fUnzippedDirRoot; private final URI assessmentObjectUri; @@ -193,12 +194,17 @@ public class AssessmentResultController extends FormBasicController { } } - testSessionState = qtiService.loadTestSessionState(candidateSession); - assessmentResult = qtiService.getAssessmentResult(candidateSession); - candidateSessionContext = new TerminatedStaticCandidateSessionContext(candidateSession); - List<AssessmentItemSession> itemSessions = qtiService.getAssessmentItemSessions(candidateSession); - for(AssessmentItemSession itemSession:itemSessions) { - identifierToItemSession.put(itemSession.getAssessmentItemIdentifier(), itemSession); + try { + testSessionState = qtiService.loadTestSessionState(candidateSession); + assessmentResult = qtiService.getAssessmentResult(candidateSession); + candidateSessionContext = new TerminatedStaticCandidateSessionContext(candidateSession); + List<AssessmentItemSession> itemSessions = qtiService.getAssessmentItemSessions(candidateSession); + for(AssessmentItemSession itemSession:itemSessions) { + identifierToItemSession.put(itemSession.getAssessmentItemIdentifier(), itemSession); + } + } catch(Exception e) { + logError("Cannot show results", e); + testSessionError = true; } initForm(ureq); @@ -214,8 +220,7 @@ public class AssessmentResultController extends FormBasicController { } else { layoutCont.contextPut("userDisplayName", Boolean.FALSE); } - - + if(testSessionState == null || assessmentResult == null) { // An author has deleted the test session before the user end it. // It can happen with time limited tests. @@ -223,6 +228,9 @@ public class AssessmentResultController extends FormBasicController { layoutCont.contextPut("testResults", results); layoutCont.contextPut("itemResults", new ArrayList<>()); layoutCont.contextPut("testSessionNotFound", Boolean.TRUE); + if(testSessionError) { + layoutCont.contextPut("testSessionError", Boolean.TRUE); + } } else { if (candidateSession != null) { 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 fd05006c2e424eae8889d892bc04d0345f503309..05ada4949fcbb1cbc7d043b18929786a2751f73d 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java @@ -85,6 +85,7 @@ import org.olat.ims.qti21.model.xml.QtiNodesExtractor; import org.olat.ims.qti21.ui.QTI21AssessmentTestSessionTableModel.TSCols; import org.olat.ims.qti21.ui.assessment.CorrectionIdentityAssessmentItemListController; import org.olat.ims.qti21.ui.assessment.CorrectionOverviewModel; +import org.olat.ims.qti21.ui.components.AssessmentTestSessionDetailsNumberRenderer; import org.olat.modules.ModuleConfiguration; import org.olat.modules.assessment.AssessmentEntry; import org.olat.modules.assessment.AssessmentService; @@ -221,9 +222,9 @@ public class QTI21AssessmentDetailsController extends FormBasicController { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.terminationTime)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.lastModified)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.duration, new TextFlexiCellRenderer(EscapeMode.none))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.numOfItemSessions, new TextFlexiCellRenderer(EscapeMode.none))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.responded, new TextFlexiCellRenderer(EscapeMode.none))); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.corrected, new TextFlexiCellRenderer(EscapeMode.none))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.numOfItemSessions, new AssessmentTestSessionDetailsNumberRenderer(getTranslator()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.responded, new AssessmentTestSessionDetailsNumberRenderer(getTranslator()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.corrected, new AssessmentTestSessionDetailsNumberRenderer(getTranslator()))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.score, new TextFlexiCellRenderer(EscapeMode.none))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.manualScore, new TextFlexiCellRenderer(EscapeMode.none))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.finalScore, new TextFlexiCellRenderer(EscapeMode.none))); @@ -267,17 +268,33 @@ public class QTI21AssessmentDetailsController extends FormBasicController { List<AssessmentTestSessionStatistics> sessionsStatistics = qtiService.getAssessmentTestSessionsStatistics(entry, subIdent, assessedIdentity); List<QTI21AssessmentTestSessionDetails> infos = new ArrayList<>(); for(AssessmentTestSessionStatistics sessionStatistics:sessionsStatistics) { - AssessmentTestSession testSession = sessionStatistics.getTestSession(); + infos.add(forgeDetailsRow(sessionStatistics)); + } + + Collections.sort(infos, new AssessmentTestSessionDetailsComparator()); + tableModel.setObjects(infos); + tableEl.reloadData(); + tableEl.reset(); + + if(resetButton != null) { + resetButton.setVisible(!sessionsStatistics.isEmpty()); + } + } + + private QTI21AssessmentTestSessionDetails forgeDetailsRow(AssessmentTestSessionStatistics sessionStatistics) { + AssessmentTestSession testSession = sessionStatistics.getTestSession(); + + int responded = 0; + int numOfItems = 0; + boolean error = false; + try { TestSessionState testSessionState = qtiService.loadTestSessionState(testSession); TestPlan testPlan = testSessionState.getTestPlan(); List<TestPlanNode> nodes = testPlan.getTestPlanNodeList(); - - int responded = 0; - int numOfItems = 0; for(TestPlanNode node:nodes) { TestNodeType testNodeType = node.getTestNodeType(); ItemSessionState itemSessionState = testSessionState.getItemSessionStates().get(node.getKey()); - + TestPlanNodeKey testPlanNodeKey = node.getKey(); if(testPlanNodeKey != null && testPlanNodeKey.getIdentifier() != null && testNodeType == TestNodeType.ASSESSMENT_ITEM_REF) { @@ -287,24 +304,17 @@ public class QTI21AssessmentDetailsController extends FormBasicController { } } } - QTI21AssessmentTestSessionDetails row = new QTI21AssessmentTestSessionDetails(testSession, - numOfItems, responded, sessionStatistics.getNumOfCorrectedItems()); - - FormLink tools = uifactory.addFormLink("tools_" + (++count), "tools", null, flc, Link.LINK); - row.setToolsLink(tools); - tools.setUserObject(row); - infos.add(row); - } - - - Collections.sort(infos, new AssessmentTestSessionDetailsComparator()); - tableModel.setObjects(infos); - tableEl.reloadData(); - tableEl.reset(); - - if(resetButton != null) { - resetButton.setVisible(!sessionsStatistics.isEmpty()); + } catch(Exception e) { + logError("Cannot read test results", e); + error = true; } + + QTI21AssessmentTestSessionDetails row = new QTI21AssessmentTestSessionDetails(testSession, + numOfItems, responded, sessionStatistics.getNumOfCorrectedItems(), error); + FormLink tools = uifactory.addFormLink("tools_" + (++count), "tools", null, flc, Link.LINK); + row.setToolsLink(tools); + tools.setUserObject(row); + return row; } @Override @@ -413,17 +423,24 @@ public class QTI21AssessmentDetailsController extends FormBasicController { File unzippedDirRoot = FileResourceManager.getInstance().unzipFileResource(testEntry.getOlatResource()); ResolvedAssessmentTest resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false); ManifestBuilder manifestBuilder = ManifestBuilder.read(new File(unzippedDirRoot, "imsmanifest.xml")); - TestSessionState testSessionState = qtiService.loadTestSessionState(session); - // use mutable maps to allow updates - Map<Identity,AssessmentTestSession> lastSessions = new HashMap<>(); - lastSessions.put(assessedIdentity, session); - Map<Identity, TestSessionState> testSessionStates = new HashMap<>(); - testSessionStates.put(assessedIdentity, testSessionState); - CorrectionOverviewModel model = new CorrectionOverviewModel(entry, courseNode, testEntry, - resolvedAssessmentTest, manifestBuilder, lastSessions, testSessionStates); - correctionCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel, model, assessedIdentity); - listenTo(correctionCtrl); - stackPanel.pushController(translate("correction"), correctionCtrl); + + try { + + TestSessionState testSessionState = qtiService.loadTestSessionState(session); + // use mutable maps to allow updates + Map<Identity,AssessmentTestSession> lastSessions = new HashMap<>(); + lastSessions.put(assessedIdentity, session); + Map<Identity, TestSessionState> testSessionStates = new HashMap<>(); + testSessionStates.put(assessedIdentity, testSessionState); + CorrectionOverviewModel model = new CorrectionOverviewModel(entry, courseNode, testEntry, + resolvedAssessmentTest, manifestBuilder, lastSessions, testSessionStates); + correctionCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel, model, assessedIdentity); + listenTo(correctionCtrl); + stackPanel.pushController(translate("correction"), correctionCtrl); + } catch(Exception e) { + logError("Cannot red results", e); + showError("error.assessment.test.session"); + } } private void doUpdateCourseNode(AssessmentTestSession session, AssessmentTest assessmentTest, AssessmentEntryStatus entryStatus) { diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionDetails.java b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionDetails.java index 961fe1947d7f774bc71e8f2112050156da3d2586..a4073d21edaccb28e1a6ebfd65b17b78eaffe6c3 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionDetails.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionDetails.java @@ -30,6 +30,7 @@ import org.olat.ims.qti21.AssessmentTestSession; */ public class QTI21AssessmentTestSessionDetails { + private final boolean error; private final int numOfItems; private final int numOfItemsResponded; private final int numOfItemsCorrected; @@ -38,7 +39,8 @@ public class QTI21AssessmentTestSessionDetails { private FormLink toolsLink; public QTI21AssessmentTestSessionDetails(AssessmentTestSession testSession, - int numOfItems, int numOfItemsResponded, int numOfItemsCorrected) { + int numOfItems, int numOfItemsResponded, int numOfItemsCorrected, boolean error) { + this.error = error; this.testSession = testSession; this.numOfItems = numOfItems; this.numOfItemsResponded = numOfItemsResponded; @@ -60,6 +62,10 @@ public class QTI21AssessmentTestSessionDetails { public AssessmentTestSession getTestSession() { return testSession; } + + public boolean isError() { + return error; + } public FormLink getToolsLink() { return toolsLink; diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionTableModel.java b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionTableModel.java index 0c72283c5a38e01c4e577ac364a2de39bc319b56..f58b861075b34c6b0350caa80318197cdcd236f2 100644 --- a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionTableModel.java +++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentTestSessionTableModel.java @@ -75,15 +75,9 @@ public class QTI21AssessmentTestSessionTableModel extends DefaultFlexiTableDataM return "<span class='o_ochre'>" + translator.translate("assessment.test.open") + "</span>"; } case test: return session.getTestSession().getTestEntry().getDisplayname(); - case numOfItemSessions: { - return session.getNumOfItems(); - } - case responded: { - return session.getNumOfItemsResponded(); - } - case corrected: { - return session.getNumOfItemsCorrected(); - } + case numOfItemSessions: return session.getNumOfItems(); + case responded: return session.getNumOfItemsResponded(); + case corrected: return session.getNumOfItemsCorrected(); case score: { if(session.getTestSession().getFinishTime() != null) { return AssessmentHelper.getRoundedScore(session.getTestSession().getScore()); diff --git a/src/main/java/org/olat/ims/qti21/ui/_content/assessment_results.html b/src/main/java/org/olat/ims/qti21/ui/_content/assessment_results.html index 98c2ca2b3204cb31f4e75643f2786ee5d584afd4..a9739f73c494299e328da595429b3c05a513d4ec 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_content/assessment_results.html +++ b/src/main/java/org/olat/ims/qti21/ui/_content/assessment_results.html @@ -69,7 +69,9 @@ $r.render("assessedIdentityInfos") #end -#if($r.isNotNull($testSessionNotFound) && $testSessionNotFound) +#if($r.isTrue($testSessionError)) +<div class="o_error" role="alert">$r.translate("error.assessment.test.session")</div> +#elseif($r.isTrue($testSessionNotFound)) <div class="o_warning">$r.translate("assessment.test.session.reseted")</div> #end diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties index b6e54d7a79155833d00c40afb6fc1d2a1fac2322..05e2c2f878ad269bfb46bbba70d10a590aef725a 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_de.properties @@ -104,6 +104,8 @@ error.as.directed=Alle 4 Antwortm\u00F6glichkeiten m\u00FCssen entweder mit Rich error.as.directed.kprim=Bitte beantworten Sie die Frage wie vorgegeben. error.assessment.item=Die Datei konnte nicht gelesen werden. Sie ist entweder korrupt oder mit dem falschen Format gespeichert. error.assessment.item.missing=Die Datei der Frage konnte nicht gelesen werden. +error.assessment.test.session=Die Datei des Tests Resultaten konnte nicht gelesen werden. +error.assessment.test.session.short=Fehler error.choice=Sie m\u00FCssen ein von den folgenden Optionen w\u00E4hlen. error.digital.certificate.cannotread=Zertifikat konnte nicht gelesen werden. error.digital.certificate.noPrivateKey=Es wurde kein "Private key" im Zertifikat gefunden. Sie ist erforderlich. diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties index 53cf7ead9a6a8f9a667277281c0497f7061d4cc6..d9af2a14d745dc1d792ad7ace62cc9b5cd65f37f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_en.properties @@ -104,6 +104,8 @@ error.as.directed=Please complete this interaction as directed. error.as.directed.kprim=Please complete this interaction as directed. error.assessment.item=The file cannot be interpreted. It seems corrupted or with the wrong format. error.assessment.item.missing=The file of the question cannot be read. +error.assessment.test.session=The data of the test results cannot be read. +error.assessment.test.session.short=Error error.choice=You must select one of the following options error.digital.certificate.cannotread=The certificate could not be read. error.digital.certificate.noPrivateKey=The "private key" could not be found. It is mandatory. diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionAssessmentItemListController.java b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionAssessmentItemListController.java index 08e2c1a362481030174c890cbe25be19d8c5697f..b521ef164b25fe1d2b3a9dc7874622e13c8b72a5 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionAssessmentItemListController.java +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionAssessmentItemListController.java @@ -34,6 +34,7 @@ import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; @@ -139,6 +140,11 @@ public class CorrectionAssessmentItemListController extends FormBasicController @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(model.hasErrors() && formLayout instanceof FormLayoutContainer) { + String errorMsg = getErrorMessage(); + ((FormLayoutContainer)formLayout).contextPut("errorMsg", errorMsg); + } + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ItemCols.section)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ItemCols.itemTitle, "select")); @@ -165,6 +171,16 @@ public class CorrectionAssessmentItemListController extends FormBasicController saveTestsButton.setElementCssClass("o_sel_correction_save_tests"); } + public String getErrorMessage() { + StringBuilder sb = new StringBuilder(1024); + List<Identity> identities = model.getIdentityWithErrors(); + for(Identity identity:identities) { + if(sb.length() > 0) sb.append(", "); + sb.append(userManager.getUserDisplayName(identity)); + } + return translate("error.assessment.test.session.identities", new String[] { sb.toString() }); + } + public void reloadModel() { loadModel(true, true); } diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityListController.java b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityListController.java index 726f2c1a558ab8121779466b40ff8e0ce9cdde2d..71c071322154a53389a6236c2c665d0f2f04b85f 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityListController.java +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityListController.java @@ -35,6 +35,7 @@ import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; @@ -139,6 +140,11 @@ public class CorrectionIdentityListController extends FormBasicController { @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(model.hasErrors() && formLayout instanceof FormLayoutContainer) { + String errorMsg = getErrorMessage(); + ((FormLayoutContainer)formLayout).contextPut("errorMsg", errorMsg); + } + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); if(anonymous) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCols.user, "select")); @@ -176,6 +182,16 @@ public class CorrectionIdentityListController extends FormBasicController { saveTestsButton = uifactory.addFormLink("save.tests", formLayout, Link.BUTTON); } + public String getErrorMessage() { + StringBuilder sb = new StringBuilder(1024); + List<Identity> identities = model.getIdentityWithErrors(); + for(Identity identity:identities) { + if(sb.length() > 0) sb.append(", "); + sb.append(userManager.getUserDisplayName(identity)); + } + return translate("error.assessment.test.session.identities", new String[] { sb.toString() }); + } + public void reloadModel() { loadModel(true, true); } diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionOverviewModel.java b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionOverviewModel.java index 43283150b7eb271b6689f72765184f42fe82dd50..cb0759db7be93ff0d62c0db8a47e974120c86e75 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionOverviewModel.java +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionOverviewModel.java @@ -28,8 +28,10 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.apache.logging.log4j.Logger; import org.olat.core.CoreSpringFactory; import org.olat.core.id.Identity; +import org.olat.core.logging.Tracing; import org.olat.course.CourseFactory; import org.olat.course.nodes.IQTESTCourseNode; import org.olat.course.run.environment.CourseEnvironment; @@ -57,6 +59,8 @@ import uk.ac.ed.ph.jqtiplus.state.TestSessionState; */ public class CorrectionOverviewModel { + private static final Logger log = Tracing.createLoggerFor(CorrectionOverviewModel.class); + private CourseEnvironment courseEnv; private final RepositoryEntry testEntry; @@ -66,6 +70,7 @@ public class CorrectionOverviewModel { private final ManifestBuilder manifestBuilder; private final ResolvedAssessmentTest resolvedAssessmentTest; private final Map<Identity, TestSessionState> testSessionStates; + private final Set<Identity> identityWithErrors = new HashSet<>(); private final Map<String,Boolean> manualCorrections = new ConcurrentHashMap<>(); private Map<Identity,AssessmentTestSession> lastSessions; @@ -140,6 +145,14 @@ public class CorrectionOverviewModel { return assessedIdentities; } + public boolean hasErrors() { + return !identityWithErrors.isEmpty(); + } + + public List<Identity> getIdentityWithErrors() { + return new ArrayList<>(identityWithErrors); + } + public int getNumberOfAssessedIdentities() { return assessedIdentities == null ? 0 : assessedIdentities.size(); } @@ -201,9 +214,14 @@ public class CorrectionOverviewModel { private Map<Identity, TestSessionState> getTestSessionStates(Map<Identity,AssessmentTestSession> sessions) { Map<Identity, TestSessionState> identityToStates = new HashMap<>(); for(Map.Entry<Identity, AssessmentTestSession> entry:sessions.entrySet()) { - TestSessionState sessionState = qtiService.loadTestSessionState(entry.getValue()); - if(sessionState != null) { - identityToStates.put(entry.getKey(), sessionState); + try { + TestSessionState sessionState = qtiService.loadTestSessionState(entry.getValue()); + if(sessionState != null) { + identityToStates.put(entry.getKey(), sessionState); + } + } catch (Exception e) { + log.error("Cannot read test results of: " + entry.getKey(), e); + identityWithErrors.add(entry.getKey()); } } return identityToStates; diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_assessment_item_list.html b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_assessment_item_list.html index 4d1ffea4a015191d27ac48d3faf663a7f3a14a6d..922538a33d890cdb0e71b40d0bbd64f8088bed58 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_assessment_item_list.html +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_assessment_item_list.html @@ -1,3 +1,6 @@ +#if($r.isNotEmpty($errorMsg)) + <div class="o_error" role="alert">$r.xssScan($errorMsg)</div> +#end $r.render("table") <div class="o_button_group"> $r.render("save.tests") diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_list.html b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_list.html index 4d1ffea4a015191d27ac48d3faf663a7f3a14a6d..922538a33d890cdb0e71b40d0bbd64f8088bed58 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_list.html +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_content/correction_identity_list.html @@ -1,3 +1,6 @@ +#if($r.isNotEmpty($errorMsg)) + <div class="o_error" role="alert">$r.xssScan($errorMsg)</div> +#end $r.render("table") <div class="o_button_group"> $r.render("save.tests") diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties index 637834417a384936be5342b53321e4e872558e85..6a3f065cfde35d649172639a0f5c24bd25c31bac 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_de.properties @@ -13,6 +13,7 @@ correction.assessment.items=Fragen correction.assessed.identities=Benutzer correction.alternatives=Varianten correction.auto=Auto +error.assessment.test.session.identities=Die Tests Resultaten von <strong>{0}</strong> konnten nicht gelesen werden. error.double.format=Falsches Zahlenformat. Beispiele\: 15.0, 5.5, 10, 15,0 error.in.form=Die \u00C4nderungen k\u00F6nnen nicht gespeichert werden, da bei einer oder mehreren Fragen Fehler auftreten. Die detaillierte Fehlerbeschreibung befindet sich bei der betroffenen Frage. grade.no.items=Es gibt kein Resultat f\u00FCr diese Frage zu korrigieren. diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties index 7cf2a947b7a0ea3bca2366f8358d9c787e0dc030..324458ba5248b71268a3a41b24c65b762d0762b3 100644 --- a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_en.properties @@ -12,6 +12,7 @@ correction.assessment.items=Questions correction.auto=Auto correction.min.max.score=Score need to be between {0} and {1}. correction.test.title=Grade +error.assessment.test.session.identities=The test results of <strong>{0}</strong> cannot be read. error.double.format=Wrong numeral format. Examples\: 15.0, 5.5, 10 error.in.form=The changes cannot be saved, as there are errors in one or more question items. The detailed error description can be found by the corresponding question item. grade.no.items=There is no results to correct for this question. diff --git a/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestSessionDetailsNumberRenderer.java b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestSessionDetailsNumberRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..78f0739c97296c8c0cf2d660eded80d8010d38db --- /dev/null +++ b/src/main/java/org/olat/ims/qti21/ui/components/AssessmentTestSessionDetailsNumberRenderer.java @@ -0,0 +1,39 @@ +package org.olat.ims.qti21.ui.components; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; +import org.olat.ims.qti21.ui.QTI21AssessmentTestSessionDetails; + +/** + * + * Initial date: 6 mai 2020<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class AssessmentTestSessionDetailsNumberRenderer implements FlexiCellRenderer { + + private final Translator translator; + + public AssessmentTestSessionDetailsNumberRenderer(Translator translator) { + this.translator = translator; + } + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator translate) { + + Object obj = source.getFlexiTableElement().getTableDataModel().getObject(row); + if(obj instanceof QTI21AssessmentTestSessionDetails && ((QTI21AssessmentTestSessionDetails)obj).isError()) { + target.append("<span title=\"").append(translator.translate("error.assessment.test.session")).append("\">") + .append("<i class='o_icon o_icon_error'> </i> ").append(translator.translate("error.assessment.test.session.short")) + .append("</span>"); + + } else if(cellValue != null) { + target.append(cellValue.toString()); + } + } +}