Skip to content
Snippets Groups Projects
Commit f54735fa authored by srosse's avatar srosse
Browse files

OO-4827: add popus to reopen assessment before correcting tests

parent 71bd8acc
No related branches found
No related tags found
No related merge requests found
Showing
with 465 additions and 28 deletions
...@@ -160,11 +160,11 @@ public class IdentityListCourseNodeController extends FormBasicController ...@@ -160,11 +160,11 @@ public class IdentityListCourseNodeController extends FormBasicController
private ContactFormController contactCtrl; private ContactFormController contactCtrl;
@Autowired @Autowired
private DB dbInstance; protected DB dbInstance;
@Autowired @Autowired
private UserManager userManager; private UserManager userManager;
@Autowired @Autowired
private BaseSecurity securityManager; protected BaseSecurity securityManager;
@Autowired @Autowired
private GradingService gradingService; private GradingService gradingService;
@Autowired @Autowired
...@@ -987,14 +987,14 @@ public class IdentityListCourseNodeController extends FormBasicController ...@@ -987,14 +987,14 @@ public class IdentityListCourseNodeController extends FormBasicController
ICourse course = CourseFactory.loadCourse(courseEntry); ICourse course = CourseFactory.loadCourse(courseEntry);
for(AssessedIdentityElementRow row:rows) { for(AssessedIdentityElementRow row:rows) {
Identity assessedIdentity = securityManager.loadIdentityByKey(row.getIdentityKey()); Identity assessedIdentity = securityManager.loadIdentityByKey(row.getIdentityKey());
doSetDone(assessedIdentity, courseNode, course); doSetStatus(assessedIdentity, AssessmentEntryStatus.done, courseNode, course);
dbInstance.commitAndCloseSession(); dbInstance.commitAndCloseSession();
} }
loadModel(ureq); loadModel(ureq);
} }
} }
protected void doSetDone(Identity assessedIdentity, CourseNode courseNode, ICourse course) { protected void doSetStatus(Identity assessedIdentity, AssessmentEntryStatus status, CourseNode courseNode, ICourse course) {
Roles roles = securityManager.getRoles(assessedIdentity); Roles roles = securityManager.getRoles(assessedIdentity);
IdentityEnvironment identityEnv = new IdentityEnvironment(assessedIdentity, roles); IdentityEnvironment identityEnv = new IdentityEnvironment(assessedIdentity, roles);
...@@ -1003,11 +1003,10 @@ public class IdentityListCourseNodeController extends FormBasicController ...@@ -1003,11 +1003,10 @@ public class IdentityListCourseNodeController extends FormBasicController
ScoreEvaluation scoreEval = courseAssessmentService.getAssessmentEvaluation(courseNode, assessedUserCourseEnv); ScoreEvaluation scoreEval = courseAssessmentService.getAssessmentEvaluation(courseNode, assessedUserCourseEnv);
ScoreEvaluation doneEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(), ScoreEvaluation doneEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(),
AssessmentEntryStatus.done, null, scoreEval.getCurrentRunCompletion(), status, null, scoreEval.getCurrentRunCompletion(),
scoreEval.getCurrentRunStatus(), scoreEval.getAssessmentID()); scoreEval.getCurrentRunStatus(), scoreEval.getAssessmentID());
courseAssessmentService.updateScoreEvaluation(courseNode, doneEval, assessedUserCourseEnv, courseAssessmentService.updateScoreEvaluation(courseNode, doneEval, assessedUserCourseEnv,
getIdentity(), false, Role.coach); getIdentity(), false, Role.coach);
} }
private void doUpdateCompletion(Double completion, AssessmentRunStatus status, Long assessedIdentityKey) { private void doUpdateCompletion(Double completion, AssessmentRunStatus status, Long assessedIdentityKey) {
......
...@@ -56,6 +56,7 @@ import org.olat.group.BusinessGroup; ...@@ -56,6 +56,7 @@ import org.olat.group.BusinessGroup;
import org.olat.modules.ModuleConfiguration; import org.olat.modules.ModuleConfiguration;
import org.olat.modules.assessment.AssessmentToolOptions; import org.olat.modules.assessment.AssessmentToolOptions;
import org.olat.modules.assessment.Role; import org.olat.modules.assessment.Role;
import org.olat.modules.assessment.model.AssessmentEntryStatus;
import org.olat.modules.assessment.ui.AssessedIdentityElementRow; import org.olat.modules.assessment.ui.AssessedIdentityElementRow;
import org.olat.modules.assessment.ui.AssessmentToolContainer; import org.olat.modules.assessment.ui.AssessmentToolContainer;
import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback; import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
...@@ -218,12 +219,12 @@ public class GTAIdentityListCourseNodeController extends IdentityListCourseNodeC ...@@ -218,12 +219,12 @@ public class GTAIdentityListCourseNodeController extends IdentityListCourseNodeC
} }
@Override @Override
protected void doSetDone(Identity assessedIdentity, CourseNode assessableCourseNode, ICourse course) { protected void doSetStatus(Identity assessedIdentity, AssessmentEntryStatus status, CourseNode assessableCourseNode, ICourse course) {
super.doSetDone(assessedIdentity, assessableCourseNode, course); super.doSetStatus(assessedIdentity, status, assessableCourseNode, course);
TaskList taskList = gtaManager.getTaskList(getCourseRepositoryEntry(), (GTACourseNode)assessableCourseNode); TaskList taskList = gtaManager.getTaskList(getCourseRepositoryEntry(), (GTACourseNode)assessableCourseNode);
Task task = gtaManager.getTask(assessedIdentity, taskList); Task task = gtaManager.getTask(assessedIdentity, taskList);
if(task != null) { if(task != null && status == AssessmentEntryStatus.done) {
gtaManager.updateTask(task, TaskProcess.graded, (GTACourseNode)assessableCourseNode, false, getIdentity(), Role.coach); gtaManager.updateTask(task, TaskProcess.graded, (GTACourseNode)assessableCourseNode, false, getIdentity(), Role.coach);
} }
} }
......
package org.olat.course.nodes.iq;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.form.flexible.FormItem;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
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.link.Link;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.util.Util;
import org.olat.ims.qti21.ui.ConfirmReopenAssessmentEntryController;
/**
*
* Initial date: 28 juil. 2020<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class ConfirmReopenAssessmentEntriesController extends FormBasicController {
private FormLink readOnlyButton;
private Object userObject;
private final long numOfAssessmentEntriesDone;
/**
* Confirm reopen of the assessment entries .
*
* @param ureq The user request
* @param wControl The window control
*/
public ConfirmReopenAssessmentEntriesController(UserRequest ureq, WindowControl wControl, long numOfAssessmentEntriesDone) {
super(ureq, wControl, "confirm_reopen_assessments", Util
.createPackageTranslator(ConfirmReopenAssessmentEntryController.class, ureq.getLocale()));
this.numOfAssessmentEntriesDone = numOfAssessmentEntriesDone;
initForm(ureq);
}
public Object getUserObject() {
return userObject;
}
public void setUserObject(Object userObject) {
this.userObject = userObject;
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
if(formLayout instanceof FormLayoutContainer) {
FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
String msg;
if(numOfAssessmentEntriesDone == 1) {
msg = translate("reopen.assessment.text");
} else {
msg = translate("reopen.assessments.text", new String[] { Long.toString(numOfAssessmentEntriesDone) });
}
layoutCont.contextPut("msg", msg);
}
uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl());
uifactory.addFormSubmitButton("reopen.assessment", formLayout);
readOnlyButton = uifactory.addFormLink("correction.readonly", formLayout, Link.BUTTON);
}
@Override
protected void doDispose() {
//
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(readOnlyButton == source) {
fireEvent(ureq, Event.DONE_EVENT);
}
super.formInnerEvent(ureq, source, event);
}
@Override
protected void formOK(UserRequest ureq) {
fireEvent(ureq, Event.CHANGED_EVENT);
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
}
...@@ -28,6 +28,8 @@ import java.util.Date; ...@@ -28,6 +28,8 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.GroupRoles;
import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.IdentityRef;
...@@ -49,6 +51,8 @@ import org.olat.core.gui.control.WindowControl; ...@@ -49,6 +51,8 @@ import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.media.MediaResource;
import org.olat.core.id.Identity; import org.olat.core.id.Identity;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.course.archiver.ScoreAccountingHelper; import org.olat.course.archiver.ScoreAccountingHelper;
import org.olat.course.assessment.AssessmentHelper; import org.olat.course.assessment.AssessmentHelper;
import org.olat.course.assessment.CourseAssessmentService; import org.olat.course.assessment.CourseAssessmentService;
...@@ -118,6 +122,7 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo ...@@ -118,6 +122,7 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo
private ConfirmExtraTimeController extraTimeCtrl; private ConfirmExtraTimeController extraTimeCtrl;
private ValidationXmlSignatureController validationCtrl; private ValidationXmlSignatureController validationCtrl;
private CorrectionOverviewController correctionIdentitiesCtrl; private CorrectionOverviewController correctionIdentitiesCtrl;
private ConfirmReopenAssessmentEntriesController reopenForCorrectionCtrl;
private boolean modelDirty = false; private boolean modelDirty = false;
...@@ -340,6 +345,16 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo ...@@ -340,6 +345,16 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo
} else if(event == Event.DONE_EVENT) { } else if(event == Event.DONE_EVENT) {
loadModel(ureq); loadModel(ureq);
} }
} else if(reopenForCorrectionCtrl == source) {
CorrectionOverviewController correctionCtrl = (CorrectionOverviewController)reopenForCorrectionCtrl.getUserObject();
cmc.deactivate();
cleanUp();
if(event == Event.CHANGED_EVENT) {
doReopenAssessmentEntries(correctionCtrl);
doOpenCorrection(correctionCtrl);
} else if(event == Event.DONE_EVENT) {
doOpenCorrection(correctionCtrl);
}
} }
super.event(ureq, source, event); super.event(ureq, source, event);
} }
...@@ -367,10 +382,12 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo ...@@ -367,10 +382,12 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo
@Override @Override
protected void cleanUp() { protected void cleanUp() {
removeAsListenerAndDispose(reopenForCorrectionCtrl);
removeAsListenerAndDispose(retrieveConfirmationCtr); removeAsListenerAndDispose(retrieveConfirmationCtr);
removeAsListenerAndDispose(validationCtrl); removeAsListenerAndDispose(validationCtrl);
removeAsListenerAndDispose(extraTimeCtrl); removeAsListenerAndDispose(extraTimeCtrl);
removeAsListenerAndDispose(resetDataCtrl); removeAsListenerAndDispose(resetDataCtrl);
reopenForCorrectionCtrl = null;
retrieveConfirmationCtr = null; retrieveConfirmationCtr = null;
validationCtrl = null; validationCtrl = null;
extraTimeCtrl = null; extraTimeCtrl = null;
...@@ -431,14 +448,51 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo ...@@ -431,14 +448,51 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo
private void doStartCorrection(UserRequest ureq) { private void doStartCorrection(UserRequest ureq) {
AssessmentToolOptions asOptions = getOptions(); AssessmentToolOptions asOptions = getOptions();
correctionIdentitiesCtrl = new CorrectionOverviewController(ureq, getWindowControl(), stackPanel, CorrectionOverviewController correctionCtrl = new CorrectionOverviewController(ureq, getWindowControl(), stackPanel,
getCourseEnvironment(), asOptions, (IQTESTCourseNode)courseNode); getCourseEnvironment(), asOptions, (IQTESTCourseNode)courseNode);
if(correctionIdentitiesCtrl.getNumberOfAssessedIdentities() == 0) { long numOfAssessmentEntriesDone = usersTableModel.getObjects().stream()
.filter(row -> row.getAssessmentStatus() == AssessmentEntryStatus.done)
.count();
if(correctionCtrl.getNumberOfAssessedIdentities() == 0) {
showWarning("grade.nobody"); showWarning("grade.nobody");
correctionIdentitiesCtrl = null; } else if(numOfAssessmentEntriesDone > 0) {
doReopenForCorrection(ureq, correctionCtrl, numOfAssessmentEntriesDone);
} else { } else {
listenTo(correctionIdentitiesCtrl); doOpenCorrection(correctionCtrl);
stackPanel.pushController(translate("correction.test.title"), correctionIdentitiesCtrl); }
}
private void doOpenCorrection(CorrectionOverviewController correctionCtrl) {
correctionIdentitiesCtrl = correctionCtrl;
listenTo(correctionIdentitiesCtrl);
stackPanel.pushController(translate("correction.test.title"), correctionIdentitiesCtrl);
}
private void doReopenForCorrection(UserRequest ureq, CorrectionOverviewController correctionCtrl, long numOfAssessmentEntriesDone) {
if(guardModalController(reopenForCorrectionCtrl)) return;
reopenForCorrectionCtrl = new ConfirmReopenAssessmentEntriesController(ureq, getWindowControl(), numOfAssessmentEntriesDone);
reopenForCorrectionCtrl.setUserObject(correctionCtrl);
listenTo(reopenForCorrectionCtrl);
cmc = new CloseableModalController(getWindowControl(), "close", reopenForCorrectionCtrl.getInitialComponent(),
true, translate("reopen.assessments.title"));
cmc.activate();
listenTo(cmc);
}
private void doReopenAssessmentEntries(CorrectionOverviewController correctionCtrl) {
List<Identity> assessedIdentities = correctionCtrl.getAssessedIdentities();
Set<Long> assessedIdentitiesKeys = assessedIdentities.stream()
.map(Identity::getKey)
.collect(Collectors.toSet());
List<AssessedIdentityElementRow> rows = usersTableModel.getObjects();
ICourse course = CourseFactory.loadCourse(courseEntry);
for(AssessedIdentityElementRow row:rows) {
if(row.getAssessmentStatus() == AssessmentEntryStatus.done && assessedIdentitiesKeys.contains(row.getIdentityKey())) {
Identity assessedIdentity = securityManager.loadIdentityByKey(row.getIdentityKey());
doSetStatus(assessedIdentity, AssessmentEntryStatus.inReview, courseNode, course);
dbInstance.commitAndCloseSession(); }
} }
} }
......
...@@ -47,6 +47,7 @@ import org.olat.ims.qti21.model.jpa.AssessmentTestSessionStatistics; ...@@ -47,6 +47,7 @@ import org.olat.ims.qti21.model.jpa.AssessmentTestSessionStatistics;
import org.olat.ims.qti21.model.xml.ManifestBuilder; import org.olat.ims.qti21.model.xml.ManifestBuilder;
import org.olat.ims.qti21.ui.AssessmentTestDisplayController; import org.olat.ims.qti21.ui.AssessmentTestDisplayController;
import org.olat.ims.qti21.ui.AssessmentTestSessionComparator; import org.olat.ims.qti21.ui.AssessmentTestSessionComparator;
import org.olat.ims.qti21.ui.ConfirmReopenAssessmentEntryController;
import org.olat.ims.qti21.ui.QTI21ResetDataController; import org.olat.ims.qti21.ui.QTI21ResetDataController;
import org.olat.ims.qti21.ui.QTI21RetrieveTestsController; import org.olat.ims.qti21.ui.QTI21RetrieveTestsController;
import org.olat.ims.qti21.ui.assessment.CorrectionIdentityAssessmentItemListController; import org.olat.ims.qti21.ui.assessment.CorrectionIdentityAssessmentItemListController;
...@@ -82,6 +83,7 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon ...@@ -82,6 +83,7 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon
private ConfirmExtraTimeController extraTimeCtrl; private ConfirmExtraTimeController extraTimeCtrl;
private QTI21RetrieveTestsController retrieveConfirmationCtr; private QTI21RetrieveTestsController retrieveConfirmationCtr;
private CorrectionIdentityAssessmentItemListController correctionCtrl; private CorrectionIdentityAssessmentItemListController correctionCtrl;
private ConfirmReopenAssessmentEntryController reopenForCorrectionCtrl;
private RepositoryEntry testEntry; private RepositoryEntry testEntry;
private RepositoryEntry courseEntry; private RepositoryEntry courseEntry;
...@@ -166,7 +168,7 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon ...@@ -166,7 +168,7 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon
protected void event(UserRequest ureq, Component source, Event event) { protected void event(UserRequest ureq, Component source, Event event) {
if(correctionLink == source) { if(correctionLink == source) {
fireEvent(ureq, Event.CLOSE_EVENT); fireEvent(ureq, Event.CLOSE_EVENT);
doOpenCorrection(ureq); doCorrection(ureq);
} else if(pullTestLink == source) { } else if(pullTestLink == source) {
fireEvent(ureq, Event.CLOSE_EVENT); fireEvent(ureq, Event.CLOSE_EVENT);
doConfirmPullSession(ureq, lastSession); doConfirmPullSession(ureq, lastSession);
...@@ -203,6 +205,10 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon ...@@ -203,6 +205,10 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon
cmc.deactivate(); cmc.deactivate();
cleanUp(); cleanUp();
fireAlteredEvent(ureq, event); fireAlteredEvent(ureq, event);
} else if(reopenForCorrectionCtrl == source) {
cmc.deactivate();
cleanUp();
doOpenCorrection(ureq);
} else if(cmc == source) { } else if(cmc == source) {
cleanUp(); cleanUp();
fireEvent(ureq, Event.CHANGED_EVENT); fireEvent(ureq, Event.CHANGED_EVENT);
...@@ -221,17 +227,42 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon ...@@ -221,17 +227,42 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon
} }
private void cleanUp() { private void cleanUp() {
removeAsListenerAndDispose(reopenForCorrectionCtrl);
removeAsListenerAndDispose(correctionCtrl); removeAsListenerAndDispose(correctionCtrl);
removeAsListenerAndDispose(extraTimeCtrl); removeAsListenerAndDispose(extraTimeCtrl);
removeAsListenerAndDispose(resetDataCtrl); removeAsListenerAndDispose(resetDataCtrl);
removeAsListenerAndDispose(cmc); removeAsListenerAndDispose(cmc);
reopenForCorrectionCtrl = null;
correctionCtrl = null; correctionCtrl = null;
extraTimeCtrl = null; extraTimeCtrl = null;
resetDataCtrl = null; resetDataCtrl = null;
cmc = null; cmc = null;
} }
private void doCorrection(UserRequest ureq) {
boolean assessmentEntryDone = isAssessementEntryDone();
if(assessmentEntryDone) {
doReopenForCorrection(ureq);
} else {
doOpenCorrection(ureq);
}
}
private void doReopenForCorrection(UserRequest ureq) {
if(guardModalController(reopenForCorrectionCtrl)) return;
reopenForCorrectionCtrl = new ConfirmReopenAssessmentEntryController(ureq, getWindowControl(),
assessedUserCourseEnv, (IQTESTCourseNode)courseNode, null);
listenTo(reopenForCorrectionCtrl);
cmc = new CloseableModalController(getWindowControl(), "close", reopenForCorrectionCtrl.getInitialComponent(),
true, translate("reopen.assessment.title"));
cmc.activate();
listenTo(cmc);
}
private void doOpenCorrection(UserRequest ureq) { private void doOpenCorrection(UserRequest ureq) {
boolean assessmentEntryDone = isAssessementEntryDone();
File unzippedDirRoot = FileResourceManager.getInstance().unzipFileResource(testEntry.getOlatResource()); File unzippedDirRoot = FileResourceManager.getInstance().unzipFileResource(testEntry.getOlatResource());
ResolvedAssessmentTest resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false); ResolvedAssessmentTest resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false);
ManifestBuilder manifestBuilder = ManifestBuilder.read(new File(unzippedDirRoot, "imsmanifest.xml")); ManifestBuilder manifestBuilder = ManifestBuilder.read(new File(unzippedDirRoot, "imsmanifest.xml"));
...@@ -242,8 +273,8 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon ...@@ -242,8 +273,8 @@ public class QTI21IdentityListCourseNodeToolsController extends AbstractToolsCon
testSessionStates.put(assessedIdentity, testSessionState); testSessionStates.put(assessedIdentity, testSessionState);
CorrectionOverviewModel model = new CorrectionOverviewModel(courseEntry, testCourseNode, testEntry, CorrectionOverviewModel model = new CorrectionOverviewModel(courseEntry, testCourseNode, testEntry,
resolvedAssessmentTest, manifestBuilder, lastSessionMap, testSessionStates); resolvedAssessmentTest, manifestBuilder, lastSessionMap, testSessionStates);
boolean readOnly = isAssessementEntryDone();
correctionCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel, model, assessedIdentity, readOnly); correctionCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel, model, assessedIdentity, assessmentEntryDone);
listenTo(correctionCtrl); listenTo(correctionCtrl);
stackPanel.pushController(translate("tool.correction"), correctionCtrl); stackPanel.pushController(translate("tool.correction"), correctionCtrl);
} }
......
<p>$msg</p>
<div class="o_button_group">
$r.render("cancel")
#if($r.available("reopen.assessment"))
$r.render("reopen.assessment")
#end
#if($r.available("correction.readonly"))
$r.render("correction.readonly")
#end
</div>
\ No newline at end of file
...@@ -165,6 +165,9 @@ qti.form.test.date.confirm=W\u00E4hrend dem Testzeitraum kann der Test gestartet ...@@ -165,6 +165,9 @@ qti.form.test.date.confirm=W\u00E4hrend dem Testzeitraum kann der Test gestartet
qti.form.test.date.help=$\:qti.form.test.date.confirm qti.form.test.date.help=$\:qti.form.test.date.confirm
qti.form.test.title=Test qti.form.test.title=Test
reopen=Erneut starten reopen=Erneut starten
reopen.assessments.title=Abgeschlossene Bewertungen wieder\u00F6ffnen
reopen.assessment.text=Es gibt eine Bewertung die schon abgeschlossen ist. Wollen Sie sie wieder\u00F6ffnen um Tests zu korrigieren?
reopen.assessments.text=Es gibt {0} Bewertungen die schon abgeschlossen sind. Wollen Sie sie wieder\u00F6ffnen um Tests zu korrigieren?
reopen.explanation=Dieser Test wurde beendet. Sie k\u00F6nnen den Test erneut starten. Der Testteilnehmende kann den Test dann dort weiterf\u00FChren, wo er aufgeh\u00F6rt hat. Falls der Test auf 1 Versuch beschr\u00E4nkt ist, m\u00FCssen au�erdem die Versuche zur\u00FCckgesetzt werden, damit der Testteilnehmende den Test weiterf\u00FChren kann. reopen.explanation=Dieser Test wurde beendet. Sie k\u00F6nnen den Test erneut starten. Der Testteilnehmende kann den Test dann dort weiterf\u00FChren, wo er aufgeh\u00F6rt hat. Falls der Test auf 1 Versuch beschr\u00E4nkt ist, m\u00FCssen au�erdem die Versuche zur\u00FCckgesetzt werden, damit der Testteilnehmende den Test weiterf\u00FChren kann.
reopen.test=Beendeten Test wieder \u00F6ffnen reopen.test=Beendeten Test wieder \u00F6ffnen
replace.wizard.information.empty.results=<b>HINWEIS\: Dieser Test/Fragebogen wurde bereits von {0} Teilnehmer(n) begonnen\!</b> Die bisherigen Ergebnisse dieser Nutzer werden mit Klick auf "Fertigstellen" im n\u00E4chsten Schritt gel\u00F6scht.<br /><br /><b>Publizieren Sie schnellstm\u00F6glich Ihren Kurs\!</b> Erst nach dem Publizieren des Kurses k\u00F6nnen die Kursteilnehmer den neu zugeordneten Test/Fragebogen starten und entsprechende Ergebnisse gespeichert werden. replace.wizard.information.empty.results=<b>HINWEIS\: Dieser Test/Fragebogen wurde bereits von {0} Teilnehmer(n) begonnen\!</b> Die bisherigen Ergebnisse dieser Nutzer werden mit Klick auf "Fertigstellen" im n\u00E4chsten Schritt gel\u00F6scht.<br /><br /><b>Publizieren Sie schnellstm\u00F6glich Ihren Kurs\!</b> Erst nach dem Publizieren des Kurses k\u00F6nnen die Kursteilnehmer den neu zugeordneten Test/Fragebogen starten und entsprechende Ergebnisse gespeichert werden.
......
...@@ -166,6 +166,9 @@ qti.form.test.date.confirm=During the test period the test can be started. As s ...@@ -166,6 +166,9 @@ qti.form.test.date.confirm=During the test period the test can be started. As s
qti.form.test.date.help=$\:qti.form.test.date.confirm qti.form.test.date.help=$\:qti.form.test.date.confirm
qti.form.test.title=Test qti.form.test.title=Test
reopen=Start again reopen=Start again
reopen.assessments.title=Reopen closed assessments
reopen.assessment.text=There is an already closed assessment. Do you want to reopen it to correct the tests?
reopen.assessments.text=There are already closed {0} assessments. Do you want to reopen them to correct the tests?
reopen.explanation=This test has been finished. You can restart the test. The test participant continues the test where he left it. If the test is limited to 1 attempt, the number of attempts must be reset so the test participants can continue the test. reopen.explanation=This test has been finished. You can restart the test. The test participant continues the test where he left it. If the test is limited to 1 attempt, the number of attempts must be reset so the test participants can continue the test.
reopen.test=Reopen finished test reopen.test=Reopen finished test
replace.wizard.information.empty.results=<b>NOTE\: This test/questionnaire has already been launched by {0} participant(s)\!</b> All user results already existing will be deleted by clicking next on "Finish".<br></br><b>Please publish your course as soon as possible\!</b> Only after publishing will course participants be able to launch your newly assigned test/questionnaire; any results can then be saved accordingly. replace.wizard.information.empty.results=<b>NOTE\: This test/questionnaire has already been launched by {0} participant(s)\!</b> All user results already existing will be deleted by clicking next on "Finish".<br></br><b>Please publish your course as soon as possible\!</b> Only after publishing will course participants be able to launch your newly assigned test/questionnaire; any results can then be saved accordingly.
......
package org.olat.ims.qti21.ui;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.form.flexible.FormItem;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
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.link.Link;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.course.assessment.CourseAssessmentService;
import org.olat.course.nodes.IQTESTCourseNode;
import org.olat.course.run.scoring.ScoreEvaluation;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.ims.qti21.AssessmentTestSession;
import org.olat.modules.assessment.AssessmentEntry;
import org.olat.modules.assessment.AssessmentService;
import org.olat.modules.assessment.Role;
import org.olat.modules.assessment.model.AssessmentEntryStatus;
import org.olat.repository.RepositoryEntry;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* Initial date: 28 juil. 2020<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class ConfirmReopenAssessmentEntryController extends FormBasicController {
private FormLink readOnlyButton;
private Object userObject;
private final IQTESTCourseNode courseNode;
private final AssessmentTestSession session;
private final UserCourseEnvironment assessedUserCourseEnv;
@Autowired
private AssessmentService assessmentService;
@Autowired
private CourseAssessmentService courseAssessmentService;
/**
* Confirm reopen of the assessment in a course element.
*
* @param ureq The user request
* @param wControl The window control
* @param assessedUserCourseEnv The user course environment of the assessed identity
* @param courseNode The course node
* @param session The assessment test session
*/
public ConfirmReopenAssessmentEntryController(UserRequest ureq, WindowControl wControl,
UserCourseEnvironment assessedUserCourseEnv, IQTESTCourseNode courseNode,
AssessmentTestSession session) {
super(ureq, wControl, "confirm_reopen_assessment");
this.assessedUserCourseEnv = assessedUserCourseEnv;
this.courseNode = courseNode;
this.session = session;
initForm(ureq);
}
/**
* Confirm reopen of the assessment of test done within a test
* repository entry.
*
* @param ureq The user request
* @param wControl The window control
* @param session The assessment test session
*/
public ConfirmReopenAssessmentEntryController(UserRequest ureq, WindowControl wControl,
AssessmentTestSession session) {
super(ureq, wControl, "confirm_reopen_assessment");
assessedUserCourseEnv = null;
courseNode = null;
this.session = session;
initForm(ureq);
}
public AssessmentTestSession getAssessmentTestSession() {
return session;
}
public Object getUserObject() {
return userObject;
}
public void setUserObject(Object userObject) {
this.userObject = userObject;
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl());
uifactory.addFormSubmitButton("reopen.assessment", formLayout);
readOnlyButton = uifactory.addFormLink("correction.readonly", formLayout, Link.BUTTON);
}
@Override
protected void doDispose() {
//
}
@Override
protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(readOnlyButton == source) {
fireEvent(ureq, Event.DONE_EVENT);
}
super.formInnerEvent(ureq, source, event);
}
@Override
protected void formOK(UserRequest ureq) {
doReopen();
fireEvent(ureq, Event.CHANGED_EVENT);
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
private void doReopen() {
if(courseNode != null) {
ScoreEvaluation scoreEval = assessedUserCourseEnv.getScoreAccounting().evalCourseNode(courseNode);
if (scoreEval != null) {
ScoreEvaluation reopenedEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(),
AssessmentEntryStatus.inReview, scoreEval.getUserVisible(), scoreEval.getCurrentRunCompletion(),
scoreEval.getCurrentRunStatus(), scoreEval.getAssessmentID());
courseAssessmentService.updateScoreEvaluation(courseNode, reopenedEval, assessedUserCourseEnv,
getIdentity(), false, Role.coach);
}
} else if(session != null) {
RepositoryEntry testEntry = session.getTestEntry();
AssessmentEntry assessmentEntry = assessmentService.loadAssessmentEntry(session.getIdentity(), testEntry, null, testEntry);
if (assessmentEntry != null) {
assessmentEntry.setAssessmentStatus(AssessmentEntryStatus.inReview);
assessmentService.updateAssessmentEntry(assessmentEntry);
}
}
}
}
...@@ -143,6 +143,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController { ...@@ -143,6 +143,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
private DialogBoxController retrieveConfirmationCtr; private DialogBoxController retrieveConfirmationCtr;
private CloseableCalloutWindowController calloutCtrl; private CloseableCalloutWindowController calloutCtrl;
private CorrectionIdentityAssessmentItemListController correctionCtrl; private CorrectionIdentityAssessmentItemListController correctionCtrl;
private ConfirmReopenAssessmentEntryController reopenForCorrectionCtrl;
private ConfirmAssessmentTestSessionInvalidationController invalidateConfirmationCtr; private ConfirmAssessmentTestSessionInvalidationController invalidateConfirmationCtr;
private ConfirmAssessmentTestSessionRevalidationController revalidateConfirmationCtr; private ConfirmAssessmentTestSessionRevalidationController revalidateConfirmationCtr;
...@@ -376,6 +377,15 @@ public class QTI21AssessmentDetailsController extends FormBasicController { ...@@ -376,6 +377,15 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
} }
cmc.deactivate(); cmc.deactivate();
cleanUp(); cleanUp();
} else if(reopenForCorrectionCtrl == source) {
cmc.deactivate();
AssessmentTestSession session = reopenForCorrectionCtrl.getAssessmentTestSession();
cleanUp();
if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
fireEvent(ureq, Event.CHANGED_EVENT);
AssessmentTestSession testSession = qtiService.getAssessmentTestSession(session.getKey());
doOpenCorrection(ureq, testSession);
}
} else if(toolsCtrl == source) { } else if(toolsCtrl == source) {
if(event == Event.DONE_EVENT) { if(event == Event.DONE_EVENT) {
calloutCtrl.deactivate(); calloutCtrl.deactivate();
...@@ -389,6 +399,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController { ...@@ -389,6 +399,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
removeAsListenerAndDispose(invalidateConfirmationCtr); removeAsListenerAndDispose(invalidateConfirmationCtr);
removeAsListenerAndDispose(revalidateConfirmationCtr); removeAsListenerAndDispose(revalidateConfirmationCtr);
removeAsListenerAndDispose(retrieveConfirmationCtr); removeAsListenerAndDispose(retrieveConfirmationCtr);
removeAsListenerAndDispose(reopenForCorrectionCtrl);
removeAsListenerAndDispose(correctionCtrl); removeAsListenerAndDispose(correctionCtrl);
removeAsListenerAndDispose(resetToolCtrl); removeAsListenerAndDispose(resetToolCtrl);
removeAsListenerAndDispose(calloutCtrl); removeAsListenerAndDispose(calloutCtrl);
...@@ -398,6 +409,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController { ...@@ -398,6 +409,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
invalidateConfirmationCtr = null; invalidateConfirmationCtr = null;
revalidateConfirmationCtr = null; revalidateConfirmationCtr = null;
retrieveConfirmationCtr = null; retrieveConfirmationCtr = null;
reopenForCorrectionCtrl = null;
correctionCtrl = null; correctionCtrl = null;
resetToolCtrl = null; resetToolCtrl = null;
calloutCtrl = null; calloutCtrl = null;
...@@ -443,6 +455,16 @@ public class QTI21AssessmentDetailsController extends FormBasicController { ...@@ -443,6 +455,16 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
} }
private void doCorrection(UserRequest ureq, AssessmentTestSession session) { private void doCorrection(UserRequest ureq, AssessmentTestSession session) {
boolean assessmentEntryDone = isAssessmentEntryDone();
if(assessmentEntryDone && !readOnly) {
confirmReopenAssessment(ureq, session);
} else {
doOpenCorrection(ureq, session);
}
}
private void doOpenCorrection(UserRequest ureq, AssessmentTestSession session) {
boolean assessmentEntryDone = isAssessmentEntryDone();
RepositoryEntry testEntry = session.getTestEntry(); RepositoryEntry testEntry = session.getTestEntry();
File unzippedDirRoot = FileResourceManager.getInstance().unzipFileResource(testEntry.getOlatResource()); File unzippedDirRoot = FileResourceManager.getInstance().unzipFileResource(testEntry.getOlatResource());
ResolvedAssessmentTest resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false); ResolvedAssessmentTest resolvedAssessmentTest = qtiService.loadAndResolveAssessmentTest(unzippedDirRoot, false, false);
...@@ -454,11 +476,11 @@ public class QTI21AssessmentDetailsController extends FormBasicController { ...@@ -454,11 +476,11 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
lastSessions.put(assessedIdentity, session); lastSessions.put(assessedIdentity, session);
Map<Identity, TestSessionState> testSessionStates = new HashMap<>(); Map<Identity, TestSessionState> testSessionStates = new HashMap<>();
testSessionStates.put(assessedIdentity, testSessionState); testSessionStates.put(assessedIdentity, testSessionState);
boolean assessmentEntryDone = isCorrectionReadOnly(); boolean correctionReadOnly = readOnly || assessmentEntryDone;
CorrectionOverviewModel model = new CorrectionOverviewModel(entry, courseNode, testEntry, CorrectionOverviewModel model = new CorrectionOverviewModel(entry, courseNode, testEntry,
resolvedAssessmentTest, manifestBuilder, lastSessions, testSessionStates); resolvedAssessmentTest, manifestBuilder, lastSessions, testSessionStates);
correctionCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel, correctionCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel,
model, assessedIdentity, assessmentEntryDone); model, assessedIdentity, correctionReadOnly);
listenTo(correctionCtrl); listenTo(correctionCtrl);
stackPanel.pushController(translate("correction"), correctionCtrl); stackPanel.pushController(translate("correction"), correctionCtrl);
} catch(Exception e) { } catch(Exception e) {
...@@ -467,9 +489,20 @@ public class QTI21AssessmentDetailsController extends FormBasicController { ...@@ -467,9 +489,20 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
} }
} }
private boolean isCorrectionReadOnly() { private void confirmReopenAssessment(UserRequest ureq, AssessmentTestSession session) {
if(readOnly) return true; if(guardModalController(reopenForCorrectionCtrl)) return;
reopenForCorrectionCtrl = new ConfirmReopenAssessmentEntryController(ureq, getWindowControl(),
assessedUserCourseEnv, courseNode, session);
listenTo(reopenForCorrectionCtrl);
cmc = new CloseableModalController(getWindowControl(), "close", reopenForCorrectionCtrl.getInitialComponent(),
true, translate("reopen.assessment.title"));
cmc.activate();
listenTo(cmc);
}
private boolean isAssessmentEntryDone() {
if(assessedUserCourseEnv != null) { if(assessedUserCourseEnv != null) {
AssessmentEvaluation eval = assessedUserCourseEnv.getScoreAccounting().getScoreEvaluation(courseNode); AssessmentEvaluation eval = assessedUserCourseEnv.getScoreAccounting().getScoreEvaluation(courseNode);
return eval != null && eval.getAssessmentStatus() == AssessmentEntryStatus.done; return eval != null && eval.getAssessmentStatus() == AssessmentEntryStatus.done;
......
<p>$r.translate("reopen.assessment.text")</p>
<div class="o_button_group">
$r.render("cancel")
#if($r.available("reopen.assessment"))
$r.render("reopen.assessment")
#end
#if($r.available("correction.readonly"))
$r.render("correction.readonly")
#end
</div>
\ No newline at end of file
...@@ -80,6 +80,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend ...@@ -80,6 +80,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend
confirmation=Best\u00E4tigung confirmation=Best\u00E4tigung
correct.solution=Korrekte L\u00F6sung correct.solution=Korrekte L\u00F6sung
correction=Korrigieren correction=Korrigieren
correction.readonly=Korrektur nur sehen
correction.workflow=Korrekturworkflow correction.workflow=Korrekturworkflow
correction.workflow.anonymous=Anonym correction.workflow.anonymous=Anonym
countdown.running=Zeitlimit {1} Sekunden\: nur <strong>{0} Sekunden \u00FCbrigs</strong> countdown.running=Zeitlimit {1} Sekunden\: nur <strong>{0} Sekunden \u00FCbrigs</strong>
...@@ -193,6 +194,9 @@ question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore ...@@ -193,6 +194,9 @@ question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore
question.progress.score=$org.olat.modules.iq\:actualPoints question.progress.score=$org.olat.modules.iq\:actualPoints
question.title=Frage {0} question.title=Frage {0}
questions=Anzahl Fragen im Test questions=Anzahl Fragen im Test
reopen.assessment=Bewertung wiederffnen
reopen.assessment.title=Abgeschlossene Bewertung wieder\u00F6ffnen
reopen.assessment.text=Diese Bewertung ist schon abgeschlossen. Wollen Sie sie wieder\u00F6ffnen um den Test zu korrigieren?
reset.data=Daten zur\u00FCcksetzen reset.data=Daten zur\u00FCcksetzen
reset.test.data.acknowledge=Ich verstehe, dass die Daten endg\u00FCltig gel\u00F6scht werden. reset.test.data.acknowledge=Ich verstehe, dass die Daten endg\u00FCltig gel\u00F6scht werden.
reset.test.data.text=Wollen Sie wirklich alle Daten von dem Test zur\u00FCcksetzen? Die Resultate von <strong>{0} Benutzern</strong> werden definitiv gel\u00F6scht. reset.test.data.text=Wollen Sie wirklich alle Daten von dem Test zur\u00FCcksetzen? Die Resultate von <strong>{0} Benutzern</strong> werden definitiv gel\u00F6scht.
......
...@@ -80,6 +80,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend ...@@ -80,6 +80,7 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend
confirmation=Confirmation confirmation=Confirmation
correct.solution=Correct solution correct.solution=Correct solution
correction=Grade correction=Grade
correction.readonly=See correction read only
correction.workflow=Correction workflow correction.workflow=Correction workflow
correction.workflow.anonymous=Anonymous correction.workflow.anonymous=Anonymous
countdown.running=Time limit {1} seconds\: <strong>{0} seconds left</strong> countdown.running=Time limit {1} seconds\: <strong>{0} seconds left</strong>
...@@ -193,6 +194,9 @@ question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore ...@@ -193,6 +194,9 @@ question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore
question.progress.score=$org.olat.modules.iq\:actualPoints question.progress.score=$org.olat.modules.iq\:actualPoints
question.title=Question {0} question.title=Question {0}
questions=Number of questions in test questions=Number of questions in test
reopen.assessment=Reopen assessment
reopen.assessment.title=Reopen closed assessment
reopen.assessment.text=This assessment ist already closed. Do you want to reopen it to correct the test?
reset.data=Reset data reset.data=Reset data
reset.test.data.acknowledge=I understand that the data will be definitely deleted. reset.test.data.acknowledge=I understand that the data will be definitely deleted.
reset.test.data.text=Do you really want to reset the assessment data of test? The results of <strong>{0} users</strong> will be definitively deleted. reset.test.data.text=Do you really want to reset the assessment data of test? The results of <strong>{0} users</strong> will be definitively deleted.
......
...@@ -469,10 +469,10 @@ public class CorrectionAssessmentItemListController extends FormBasicController ...@@ -469,10 +469,10 @@ public class CorrectionAssessmentItemListController extends FormBasicController
itemRef, itemNode); itemRef, itemNode);
itemCorrection.setItemSession(reloadItemSession); itemCorrection.setItemSession(reloadItemSession);
boolean readOnly = model.isReadOnly(assessedIdentity); boolean assessmentEntryDone = model.isAssessmentEntryDone(assessedIdentity);
identityItemCtrl = new CorrectionIdentityAssessmentItemNavigationController(ureq, getWindowControl(), identityItemCtrl = new CorrectionIdentityAssessmentItemNavigationController(ureq, getWindowControl(),
model.getTestEntry(), model.getResolvedAssessmentTest(), itemCorrection, listEntry, model.getTestEntry(), model.getResolvedAssessmentTest(), itemCorrection, listEntry,
selectedItemSessions, model, null, readOnly, true); selectedItemSessions, model, null, assessmentEntryDone, true);
listenTo(identityItemCtrl); listenTo(identityItemCtrl);
updatePreviousNext(); updatePreviousNext();
......
...@@ -52,11 +52,14 @@ import org.olat.core.id.Identity; ...@@ -52,11 +52,14 @@ import org.olat.core.id.Identity;
import org.olat.core.id.Roles; import org.olat.core.id.Roles;
import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.LockResult; import org.olat.core.util.coordinate.LockResult;
import org.olat.course.assessment.AssessmentHelper;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.ims.qti21.AssessmentItemSession; import org.olat.ims.qti21.AssessmentItemSession;
import org.olat.ims.qti21.AssessmentTestSession; import org.olat.ims.qti21.AssessmentTestSession;
import org.olat.ims.qti21.QTI21Module; import org.olat.ims.qti21.QTI21Module;
import org.olat.ims.qti21.QTI21Module.CorrectionWorkflow; import org.olat.ims.qti21.QTI21Module.CorrectionWorkflow;
import org.olat.ims.qti21.QTI21Service; import org.olat.ims.qti21.QTI21Service;
import org.olat.ims.qti21.ui.ConfirmReopenAssessmentEntryController;
import org.olat.ims.qti21.ui.assessment.CorrectionIdentityTableModel.IdentityCols; import org.olat.ims.qti21.ui.assessment.CorrectionIdentityTableModel.IdentityCols;
import org.olat.ims.qti21.ui.assessment.components.CorrectedFlexiCellRenderer; import org.olat.ims.qti21.ui.assessment.components.CorrectedFlexiCellRenderer;
import org.olat.ims.qti21.ui.assessment.components.NotCorrectedFlexiCellRenderer; import org.olat.ims.qti21.ui.assessment.components.NotCorrectedFlexiCellRenderer;
...@@ -98,6 +101,7 @@ public class CorrectionIdentityListController extends FormBasicController { ...@@ -98,6 +101,7 @@ public class CorrectionIdentityListController extends FormBasicController {
private CloseableModalController cmc; private CloseableModalController cmc;
private ConfirmSaveTestsController confirmSaveTestCtrl; private ConfirmSaveTestsController confirmSaveTestCtrl;
private ConfirmReopenAssessmentEntryController reopenForCorrectionCtrl;
private CorrectionIdentityAssessmentItemListController identityItemListCtrl; private CorrectionIdentityAssessmentItemListController identityItemListCtrl;
private final boolean isAdministrativeUser; private final boolean isAdministrativeUser;
...@@ -320,6 +324,14 @@ public class CorrectionIdentityListController extends FormBasicController { ...@@ -320,6 +324,14 @@ public class CorrectionIdentityListController extends FormBasicController {
} }
cmc.deactivate(); cmc.deactivate();
cleanUp(); cleanUp();
} else if(reopenForCorrectionCtrl == source) {
cmc.deactivate();
CorrectionIdentityRow row = (CorrectionIdentityRow)reopenForCorrectionCtrl.getUserObject();
cleanUp();
if(event == Event.CHANGED_EVENT || event == Event.DONE_EVENT) {
model.discardAssessmentEntryDone(row.getIdentity());
doOpenCorrection(ureq, row);
}
} else if(cmc == source) { } else if(cmc == source) {
cleanUp(); cleanUp();
} }
...@@ -327,8 +339,10 @@ public class CorrectionIdentityListController extends FormBasicController { ...@@ -327,8 +339,10 @@ public class CorrectionIdentityListController extends FormBasicController {
} }
private void cleanUp() { private void cleanUp() {
removeAsListenerAndDispose(reopenForCorrectionCtrl);
removeAsListenerAndDispose(confirmSaveTestCtrl); removeAsListenerAndDispose(confirmSaveTestCtrl);
removeAsListenerAndDispose(cmc); removeAsListenerAndDispose(cmc);
reopenForCorrectionCtrl = null;
confirmSaveTestCtrl = null; confirmSaveTestCtrl = null;
cmc = null; cmc = null;
} }
...@@ -361,10 +375,36 @@ public class CorrectionIdentityListController extends FormBasicController { ...@@ -361,10 +375,36 @@ public class CorrectionIdentityListController extends FormBasicController {
} }
Identity assessedIdentity = row.getIdentity(); Identity assessedIdentity = row.getIdentity();
boolean readOnly = model.isReadOnly(assessedIdentity); boolean assessmentEntryDone = model.isAssessmentEntryDone(assessedIdentity);
if(assessmentEntryDone) {
doReopenForCorrection(ureq, row);
} else {
doOpenCorrection(ureq, row);
}
}
private void doReopenForCorrection(UserRequest ureq, CorrectionIdentityRow row) {
if(guardModalController(reopenForCorrectionCtrl)) return;
UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper
.createAndInitUserCourseEnvironment(row.getIdentity(), model.getCourseEnvironment());
reopenForCorrectionCtrl = new ConfirmReopenAssessmentEntryController(ureq, getWindowControl(),
assessedUserCourseEnv, model.getCourseNode(), row.getCandidateSession());
reopenForCorrectionCtrl.setUserObject(row);
listenTo(reopenForCorrectionCtrl);
cmc = new CloseableModalController(getWindowControl(), "close", reopenForCorrectionCtrl.getInitialComponent(),
true, translate("reopen.assessment.title"));
cmc.activate();
listenTo(cmc);
}
private void doOpenCorrection(UserRequest ureq, CorrectionIdentityRow row) {
Identity assessedIdentity = row.getIdentity();
boolean assessmentEntryDone = model.isAssessmentEntryDone(assessedIdentity);
String title = anonymous ? row.getUser() : userManager.getUserDisplayName(row.getIdentity()); String title = anonymous ? row.getUser() : userManager.getUserDisplayName(row.getIdentity());
identityItemListCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel, identityItemListCtrl = new CorrectionIdentityAssessmentItemListController(ureq, getWindowControl(), stackPanel,
model, assessedIdentity, title, readOnly); model, assessedIdentity, title, assessmentEntryDone);
listenTo(identityItemListCtrl); listenTo(identityItemListCtrl);
String crumb; String crumb;
......
...@@ -109,7 +109,7 @@ public class CorrectionOverviewController extends BasicController implements Too ...@@ -109,7 +109,7 @@ public class CorrectionOverviewController extends BasicController implements Too
identifierToRefs.put(itemRef.getIdentifier(), itemRef); identifierToRefs.put(itemRef.getIdentifier(), itemRef);
} }
List<Identity> assessedIdentities = getAssessedIdentities(); List<Identity> assessedIdentities = initializeAssessedIdentities();
model = new CorrectionOverviewModel(courseEntry, courseNode, testEntry, model = new CorrectionOverviewModel(courseEntry, courseNode, testEntry,
resolvedAssessmentTest, manifestBuilder, assessedIdentities); resolvedAssessmentTest, manifestBuilder, assessedIdentities);
...@@ -134,7 +134,11 @@ public class CorrectionOverviewController extends BasicController implements Too ...@@ -134,7 +134,11 @@ public class CorrectionOverviewController extends BasicController implements Too
return model.getNumberOfAssessedIdentities(); return model.getNumberOfAssessedIdentities();
} }
private List<Identity> getAssessedIdentities() { public List<Identity> getAssessedIdentities() {
return model.getAssessedIdentities();
}
private List<Identity> initializeAssessedIdentities() {
Set<Identity> identitiesSet; Set<Identity> identitiesSet;
if(asOptions.getGroup() != null) { if(asOptions.getGroup() != null) {
List<Identity> identities = businessGroupService.getMembers(asOptions.getGroup(), GroupRoles.participant.name()); List<Identity> identities = businessGroupService.getMembers(asOptions.getGroup(), GroupRoles.participant.name());
......
...@@ -262,7 +262,11 @@ public class CorrectionOverviewModel { ...@@ -262,7 +262,11 @@ public class CorrectionOverviewModel {
return manifestBuilder.getResourceBuilderByHref(itemRef.getHref().toString()); return manifestBuilder.getResourceBuilderByHref(itemRef.getHref().toString());
} }
public boolean isReadOnly(Identity assessedIdentity) { public void discardAssessmentEntryDone(Identity assessedIdentity) {
assessedIdentitiesDone.remove(assessedIdentity);
}
public boolean isAssessmentEntryDone(Identity assessedIdentity) {
Boolean done = assessedIdentitiesDone.computeIfAbsent(assessedIdentity, identity -> { Boolean done = assessedIdentitiesDone.computeIfAbsent(assessedIdentity, identity -> {
if(getCourseNode() != null) { if(getCourseNode() != null) {
UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper
......
...@@ -26,6 +26,7 @@ not.responded=Die Frage wurde nicht beantwortet ...@@ -26,6 +26,7 @@ not.responded=Die Frage wurde nicht beantwortet
overview.tests=\u00DCbersicht und abschliessen overview.tests=\u00DCbersicht und abschliessen
previous.item=Vorherige Frage previous.item=Vorherige Frage
previous.user=Vorheriger Benutzer previous.user=Vorheriger Benutzer
reopen.assessment.title=$org.olat.ims.qti21.ui\:reopen.assessment.title
save.back=Speichern und zur \u00DCbersicht save.back=Speichern und zur \u00DCbersicht
save.next=Speichern und n\u00E4chste Frage save.next=Speichern und n\u00E4chste Frage
save.next.identity=Speichern und n\u00E4chster Teilnehmer save.next.identity=Speichern und n\u00E4chster Teilnehmer
......
...@@ -26,6 +26,7 @@ override.score=Override score ...@@ -26,6 +26,7 @@ override.score=Override score
overview.tests=Overview and closing overview.tests=Overview and closing
previous.item=Previous question previous.item=Previous question
previous.user=Previous user previous.user=Previous user
reopen.assessment.title=$org.olat.ims.qti21.ui\:reopen.assessment.title
save.back=Save and back to overview save.back=Save and back to overview
save.next=Save and next question save.next=Save and next question
save.next.identity=Save and next participant save.next.identity=Save and next participant
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment