From 52c19184665d21f201c5d545a36ef110bc4c3457 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Thu, 2 Jul 2020 15:36:34 +0200
Subject: [PATCH] OO-2036: handle assessment mode across several browser
 windows

---
 .../fullWebApp/BaseFullWebappController.java  | 19 ++++++-
 .../commons/fullWebApp/LockResourceInfos.java | 55 +++++++++++++++++++
 src/main/java/org/olat/core/gui/Windows.java  | 19 +++++++
 .../core/gui/control/ChiefController.java     | 16 +++++-
 .../gui/control/DefaultChiefController.java   | 10 +++-
 ...AssessmentModeCoordinationServiceImpl.java |  3 +
 .../interpreter/IsAssessmentModeFunction.java |  4 +-
 .../dispatcher/AuthenticatedDispatcher.java   | 11 +++-
 8 files changed, 127 insertions(+), 10 deletions(-)
 create mode 100644 src/main/java/org/olat/core/commons/fullWebApp/LockResourceInfos.java

diff --git a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
index 6586034fe17..e2bc2bd0465 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
+++ b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
@@ -1433,6 +1433,9 @@ public class BaseFullWebappController extends BasicController implements DTabs,
 			return;
 		}
 		
+		String instanceId = getWindow().getInstanceId();
+		System.out.println(instanceId + " " + event.getCommand());
+		
 		String cmd = event.getCommand();
 		switch(cmd) {
 			case AssessmentModeNotificationEvent.STOP_WARNING:
@@ -1478,8 +1481,9 @@ public class BaseFullWebappController extends BasicController implements DTabs,
 	}
 	
 	@Override
-	public OLATResourceable getLockResource() {
-		return lockResource;
+	public LockResourceInfos getLockResourceInfos() {
+		if(lockResource == null) return null;
+		return new LockResourceInfos(lockStatus, lockResource, lockMode);
 	}
 
 	@Override
@@ -1488,6 +1492,15 @@ public class BaseFullWebappController extends BasicController implements DTabs,
 		lockGUI();
 	}
 	
+	public void hardLockResource(LockResourceInfos lockInfos) {
+		if(lockInfos == null) return;
+		
+		lockResource = lockInfos.getLockResource();
+		lockMode = lockInfos.getLockMode();
+		lockStatus = lockInfos.getLockStatus();
+		lockGUI();
+	}
+	
 	private void lockGUI() {
 		if(topnavCtr != null) {
 			topnavCtr.lock();
@@ -1758,7 +1771,7 @@ public class BaseFullWebappController extends BasicController implements DTabs,
 		}
 	}
 	
-	private enum LockStatus {
+	protected enum LockStatus {
 		need,
 		popup,
 		locked
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/LockResourceInfos.java b/src/main/java/org/olat/core/commons/fullWebApp/LockResourceInfos.java
new file mode 100644
index 00000000000..a549e30134b
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/fullWebApp/LockResourceInfos.java
@@ -0,0 +1,55 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.fullWebApp;
+
+import org.olat.core.commons.fullWebApp.BaseFullWebappController.LockStatus;
+import org.olat.core.id.OLATResourceable;
+import org.olat.course.assessment.model.TransientAssessmentMode;
+
+/**
+ * 
+ * Initial date: 2 juil. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class LockResourceInfos {
+	
+	private final LockStatus lockStatus;
+	private final OLATResourceable lockResource;
+	private final TransientAssessmentMode lockMode; 
+	
+	public LockResourceInfos(LockStatus lockStatus, OLATResourceable lockResource, TransientAssessmentMode lockMode) {
+		this.lockStatus = lockStatus;
+		this.lockResource = lockResource;
+		this.lockMode = lockMode;
+	}
+
+	public LockStatus getLockStatus() {
+		return lockStatus;
+	}
+
+	public OLATResourceable getLockResource() {
+		return lockResource;
+	}
+
+	public TransientAssessmentMode getLockMode() {
+		return lockMode;
+	}
+}
diff --git a/src/main/java/org/olat/core/gui/Windows.java b/src/main/java/org/olat/core/gui/Windows.java
index dbba15692d8..c6acb1e4168 100644
--- a/src/main/java/org/olat/core/gui/Windows.java
+++ b/src/main/java/org/olat/core/gui/Windows.java
@@ -33,6 +33,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.olat.core.commons.fullWebApp.LockResourceInfos;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.ComponentHelper;
 import org.olat.core.gui.components.Window;
@@ -271,6 +272,24 @@ public class Windows implements Disposable, Serializable {
 		}
 		return ws.iterator();
 	}
+	
+	/**
+	 * Search all the windows to find the first locked chief controller
+	 * and returns informations about the locked resource.
+	 * 
+	 * @return Informations about the current locked resource, or null if the
+	 * 		user has not a chief controller locked.
+	 */
+	public LockResourceInfos getLockResourceInfos() {
+		List<ChiefController> chiefControllers = windows.values();
+		for(ChiefController chiefController:chiefControllers) {
+			LockResourceInfos lockInfos = chiefController.getLockResourceInfos();
+			if(lockInfos != null) {
+				return lockInfos;
+			}
+		}
+		return null;
+	}
 
 	/**
 	 * @return the number of windows
diff --git a/src/main/java/org/olat/core/gui/control/ChiefController.java b/src/main/java/org/olat/core/gui/control/ChiefController.java
index 7fbef0b54f3..7dabfb3d2f2 100644
--- a/src/main/java/org/olat/core/gui/control/ChiefController.java
+++ b/src/main/java/org/olat/core/gui/control/ChiefController.java
@@ -26,6 +26,7 @@
 
 package org.olat.core.gui.control;
 
+import org.olat.core.commons.fullWebApp.LockResourceInfos;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Window;
 import org.olat.core.gui.components.htmlheader.jscss.CustomCSS;
@@ -74,12 +75,23 @@ public interface ChiefController extends Controller {
 	public void resetReload();
 	
 	/**
+	 * Lock softly the chief after interaction with the user.
 	 * 
-	 * @param resource
+	 * @param resource The resource to lock
 	 */
 	public void lockResource(OLATResourceable resource);
 	
-	public OLATResourceable getLockResource();
+	/**
+	 * Hard locking the chief controller after a copy/paste URL or
+	 * such a thing. If the informations are null, the call is ignored.
+	 * 
+	 * @param lockInfos The lock informations
+	 */
+	public void hardLockResource(LockResourceInfos lockInfos);
+	
+	public LockResourceInfos getLockResourceInfos();
+	
+	
 	
 	/**
 	 * Set a class to the &lt;body&gt;
diff --git a/src/main/java/org/olat/core/gui/control/DefaultChiefController.java b/src/main/java/org/olat/core/gui/control/DefaultChiefController.java
index 410348ae1be..668823e50e4 100644
--- a/src/main/java/org/olat/core/gui/control/DefaultChiefController.java
+++ b/src/main/java/org/olat/core/gui/control/DefaultChiefController.java
@@ -26,6 +26,7 @@
 
 package org.olat.core.gui.control;
 
+import org.olat.core.commons.fullWebApp.LockResourceInfos;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.Window;
@@ -86,12 +87,17 @@ public abstract class DefaultChiefController extends DefaultController implement
 	}
 	
 	@Override
-	public OLATResourceable getLockResource() {
+	public final LockResourceInfos getLockResourceInfos() {
 		return null;
 	}
 
 	@Override
-	public void lockResource(OLATResourceable resource) {
+	public final void lockResource(OLATResourceable resource) {
+		//
+	}
+
+	@Override
+	public final void hardLockResource(LockResourceInfos lockInfos) {
 		//
 	}
 
diff --git a/src/main/java/org/olat/course/assessment/manager/AssessmentModeCoordinationServiceImpl.java b/src/main/java/org/olat/course/assessment/manager/AssessmentModeCoordinationServiceImpl.java
index ea5c8491c06..a7e1577b7ab 100644
--- a/src/main/java/org/olat/course/assessment/manager/AssessmentModeCoordinationServiceImpl.java
+++ b/src/main/java/org/olat/course/assessment/manager/AssessmentModeCoordinationServiceImpl.java
@@ -274,6 +274,9 @@ public class AssessmentModeCoordinationServiceImpl implements AssessmentModeCoor
 					sendEvent(AssessmentModeNotificationEvent.END, mode,
 							assessmentModeManager.getAssessedIdentityKeys(mode));
 				}
+			} else if(mode.getStatus() == Status.assessment) {
+				sendEvent(AssessmentModeNotificationEvent.START_ASSESSMENT, mode,
+						assessmentModeManager.getAssessedIdentityKeys(mode));
 			}
 		} else {
 			if(mode.getBegin().compareTo(now) <= 0 && mode.getEnd().compareTo(now) > 0) {
diff --git a/src/main/java/org/olat/course/condition/interpreter/IsAssessmentModeFunction.java b/src/main/java/org/olat/course/condition/interpreter/IsAssessmentModeFunction.java
index 725078dad38..eb8b87df327 100644
--- a/src/main/java/org/olat/course/condition/interpreter/IsAssessmentModeFunction.java
+++ b/src/main/java/org/olat/course/condition/interpreter/IsAssessmentModeFunction.java
@@ -24,6 +24,7 @@ import java.util.Date;
 import java.util.List;
 
 import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.fullWebApp.LockResourceInfos;
 import org.olat.core.gui.control.ChiefController;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.OLATResourceable;
@@ -83,7 +84,8 @@ public class IsAssessmentModeFunction extends AbstractFunction {
 		if(chiefController == null) {
 			return ConditionInterpreter.INT_FALSE;
 		}
-		OLATResourceable lockedResource = chiefController.getLockResource();
+		LockResourceInfos lockInfos = chiefController.getLockResourceInfos();
+		OLATResourceable lockedResource = lockInfos == null ? null : lockInfos.getLockResource();
 
 		boolean open = false;
 		if(inStack != null && inStack.length == 2) {
diff --git a/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java b/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java
index f90778dfd0b..c59c1c0e1d5 100644
--- a/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java
+++ b/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java
@@ -38,7 +38,9 @@ import org.apache.logging.log4j.Logger;
 import org.olat.NewControllerFactory;
 import org.olat.basesecurity.AuthHelper;
 import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.fullWebApp.BaseFullWebappController;
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
+import org.olat.core.commons.fullWebApp.LockResourceInfos;
 import org.olat.core.dispatcher.Dispatcher;
 import org.olat.core.dispatcher.DispatcherModule;
 import org.olat.core.gui.UserRequest;
@@ -313,8 +315,9 @@ public class AuthenticatedDispatcher implements Dispatcher {
 			}
 			return;
 		}
-
-		ChiefController chiefController = Windows.getWindows(usess).getChiefController(ureq);
+		
+		Windows windows = Windows.getWindows(usess);
+		ChiefController chiefController = windows.getChiefController(ureq);
 		if(chiefController == null && !usess.isAuthenticated()) {
 			redirectToDefaultDispatcher(ureq.getHttpReq(), ureq.getHttpResp());
 			return;
@@ -342,6 +345,10 @@ public class AuthenticatedDispatcher implements Dispatcher {
 				chiefController = (ChiefController)pbw;
 			} else {
 				chiefController = AuthHelper.createAuthHome(ureq);
+				LockResourceInfos lockInfos = windows.getLockResourceInfos();
+				if(lockInfos != null) {
+					((BaseFullWebappController)chiefController).hardLockResource(lockInfos);
+				}
 			}
 			Window window = chiefController.getWindow();
 			window.setUriPrefix(ureq.getUriPrefix());
-- 
GitLab