diff --git a/src/main/java/org/olat/commons/coordinate/cluster/lock/ClusterLocker.java b/src/main/java/org/olat/commons/coordinate/cluster/lock/ClusterLocker.java index a010294d325531460d0bc7a00016e48cb68af3c3..4b04c9af4b16d2a2410a092d9cd08a39ee8d1138 100644 --- a/src/main/java/org/olat/commons/coordinate/cluster/lock/ClusterLocker.java +++ b/src/main/java/org/olat/commons/coordinate/cluster/lock/ClusterLocker.java @@ -162,6 +162,16 @@ public class ClusterLocker implements Locker, GenericEventListener { final String asset = OresHelper.createStringRepresenting(ores, locksubkey); return clusterLockManager.isLocked(asset); } + + @Override + public LockEntry getLockEntry(OLATResourceable ores, String locksubkey) { + final String asset = OresHelper.createStringRepresenting(ores, locksubkey); + LockImpl li = clusterLockManager.findLock(asset); + if(li == null) { + return null; + } + return new LockEntry(li.getAsset(), li.getCreationDate().getTime(), li.getOwner()); + } @Override public Identity getLockedBy(OLATResourceable ores, String locksubkey) { diff --git a/src/main/java/org/olat/core/gui/control/generic/modal/DialogBoxUIFactory.java b/src/main/java/org/olat/core/gui/control/generic/modal/DialogBoxUIFactory.java index ab787ec982aa44f6218f14975cdc296eaaa7e719..0efbdc0927e62cb6ff95eb6f6e36dc35f27bfd85 100644 --- a/src/main/java/org/olat/core/gui/control/generic/modal/DialogBoxUIFactory.java +++ b/src/main/java/org/olat/core/gui/control/generic/modal/DialogBoxUIFactory.java @@ -37,6 +37,7 @@ import org.olat.core.logging.AssertException; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; +import org.olat.core.util.coordinate.LockEntry; import org.olat.core.util.coordinate.LockResult; import org.olat.user.UserManager; @@ -117,10 +118,7 @@ public class DialogBoxUIFactory { if(lockEntry.isSuccess()){ throw new AssertException("do not create a 'is locked message' if lock was succesfull! concerns lock:"+lockEntry.getOwner()); } - String fullName = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(lockEntry.getOwner()); - String[] i18nParams = new String[] { StringHelper.escapeHtml(fullName), - Formatter.getInstance(ureq.getLocale()).formatTime(new Date(lockEntry.getLockAquiredTime())) }; - String lockMsg = translator.translate(i18nLockMsgKey, i18nParams); + String lockMsg = getLockedMessage(ureq, lockEntry.getLockEntry(), i18nLockMsgKey, translator); Translator trans = Util.createPackageTranslator(DialogBoxUIFactory.class, ureq.getLocale()); List<String> okButton = new ArrayList<>(); @@ -131,6 +129,13 @@ public class DialogBoxUIFactory { return ctrl; } + public static String getLockedMessage(UserRequest ureq, LockEntry lockEntry, String i18nLockMsgKey, Translator translator) { + String fullName = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(lockEntry.getOwner()); + String[] i18nParams = new String[] { StringHelper.escapeHtml(fullName), + Formatter.getInstance(ureq.getLocale()).formatTime(new Date(lockEntry.getLockAquiredTime())) }; + return translator.translate(i18nLockMsgKey, i18nParams); + } + /** * checks if this event from a OkCancel Dialog is an OK event. diff --git a/src/main/java/org/olat/core/util/coordinate/Locker.java b/src/main/java/org/olat/core/util/coordinate/Locker.java index 8b7423cae2006b39b85bfbfec261806ff7f675c4..3654c9323a676bf769be0d40c4bf1ed23523986e 100644 --- a/src/main/java/org/olat/core/util/coordinate/Locker.java +++ b/src/main/java/org/olat/core/util/coordinate/Locker.java @@ -74,7 +74,14 @@ public interface Locker { * @return The identity which lock the resource or null. */ public Identity getLockedBy(OLATResourceable ores, String locksubkey); - + + /** + * + * @param ores + * @param locksubkey + * @return + */ + public LockEntry getLockEntry(OLATResourceable ores, String locksubkey); /** * diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java index 449160260e7d3ba027959095bc9b35c3edb3dbd4..01256e93f1748c3a7130a5874894fd8c19693355 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java @@ -22,6 +22,7 @@ package org.olat.course.assessment.ui.tool; import java.util.List; import org.olat.basesecurity.BaseSecurity; +import org.olat.basesecurity.IdentityRef; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.stack.TooledStackedPanel; @@ -30,7 +31,6 @@ 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.gui.control.controller.BasicController; -import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.Identity; import org.olat.core.id.IdentityEnvironment; @@ -74,7 +74,6 @@ public class AssessmentIdentityCourseNodeController extends BasicController impl private Controller identityInfosCtrl; private Controller subDetailsController; private Controller detailsEditController; - private DialogBoxController alreadyLockedDialogController; private LockResult lockEntry; private final CourseNode courseNode; @@ -106,20 +105,19 @@ public class AssessmentIdentityCourseNodeController extends BasicController impl identityAssessmentVC = createVelocityContainer("identity_personal_node_infos"); initDetails(); + + identityInfosCtrl = new AssessedIdentityLargeInfosController(ureq, wControl, assessedIdentity, course); + listenTo(identityInfosCtrl); + identityAssessmentVC.put("identityInfos", identityInfosCtrl.getInitialComponent()); //acquire lock and show dialog box on failure. - String lockSubKey = "AssessmentLock-NID::" + courseNode.getIdent() + "-IID::" + assessedIdentity.getKey(); + String lockSubKey = lockKey(courseNode, assessedIdentity); lockEntry = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(course, ureq.getIdentity(), lockSubKey); if(!lockEntry.isSuccess()) { - alreadyLockedDialogController = DialogBoxUIFactory.createResourceLockedMessage(ureq, wControl, lockEntry, "assessmentLock", getTranslator()); - listenTo(alreadyLockedDialogController); - alreadyLockedDialogController.activate(); + String msg = DialogBoxUIFactory.getLockedMessage(ureq, lockEntry.getLockEntry(), "assessmentLock", getTranslator()); + getWindowControl().setWarning(msg); } else if(courseNode instanceof AssessableCourseNode) { - AssessableCourseNode aCourseNode = (AssessableCourseNode)courseNode; - - identityInfosCtrl = new AssessedIdentityLargeInfosController(ureq, wControl, assessedIdentity, course); - listenTo(identityInfosCtrl); - identityAssessmentVC.put("identityInfos", identityInfosCtrl.getInitialComponent()); + AssessableCourseNode aCourseNode = (AssessableCourseNode)courseNode; // Add the users details controller if (aCourseNode.hasDetails() && courseNodeDetails) { @@ -140,6 +138,10 @@ public class AssessmentIdentityCourseNodeController extends BasicController impl putInitialPanel(identityAssessmentVC); } + public static String lockKey(CourseNode node, IdentityRef identity) { + return "AssessmentLock-NID::" + node.getIdent() + "-IID::" + identity.getKey(); + } + public UserCourseEnvironment getCoachCourseEnvironment() { return coachCourseEnv; } diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java index ac3e13dab442ded20e22c19aa03326ade0c188d0..0e27368c1bf3010856e0d831c36ec2a21262245b 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java @@ -59,6 +59,7 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.id.Identity; import org.olat.core.id.IdentityEnvironment; import org.olat.core.id.OLATResourceable; @@ -68,6 +69,7 @@ import org.olat.core.id.context.StateEntry; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.coordinate.CoordinatorManager; +import org.olat.core.util.coordinate.LockEntry; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; @@ -777,12 +779,42 @@ public class IdentityListCourseNodeController extends FormBasicController private void doSelect(UserRequest ureq, Identity assessedIdentity) { List<AssessedIdentityElementRow> rows = usersTableModel.getObjects(); + AssessedIdentityElementRow selectedRow = null; for(AssessedIdentityElementRow row:rows) { if(assessedIdentity.getKey().equals(row.getIdentityKey())) { - doSelect(ureq, row); + selectedRow = row; break; } } + + if(selectedRow != null && !isAssessedIdentityLocked(ureq, assessedIdentity)) { + doSelect(ureq, selectedRow); + } + } + + /** + * Preventive check if the identity is already locked by an other + * user and show a warning message if needed. + * + * @param ureq The user request + * @param assessedIdentity The identity to assess + * @return + */ + private boolean isAssessedIdentityLocked(UserRequest ureq, Identity assessedIdentity) { + if(courseNode.getParent() == null) return false; + + ICourse course = CourseFactory.loadCourse(courseEntry); + String locksubkey = AssessmentIdentityCourseNodeController.lockKey(courseNode, assessedIdentity); + if(CoordinatorManager.getInstance().getCoordinator().getLocker().isLocked(course, locksubkey)) { + LockEntry lock = CoordinatorManager.getInstance().getCoordinator().getLocker().getLockEntry(course, locksubkey); + if(lock != null && lock.getOwner() != null && !lock.getOwner().equals(getIdentity())) { + String msg = DialogBoxUIFactory.getLockedMessage(ureq, lock, "assessmentLock", getTranslator()); + getWindowControl().setWarning(msg); + return true; + } + } + + return false; } private Controller doSelect(UserRequest ureq, AssessedIdentityElementRow row) { diff --git a/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java b/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java index 5a23115242cfe6548d5c8da4b396984a53e68a31..09bce8b02ab9578d006e5c3ed01eff8fc8fd1848 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java @@ -121,8 +121,8 @@ public abstract class AbstractToolsController extends BasicController { } lastLink = link; } - if(links.size() > 0 && "-".equals(links.get(links.size() - 1))) { - links.remove(links.size() -1);//no trialing separator + if(!links.isEmpty() && "-".equals(links.get(links.size() - 1))) { + links.remove(links.size() -1);//no trailing separator } mainVC.contextPut("links", links);