From f05ea2716e2d6c4b25d057215873991cc821b200 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 4 Dec 2013 14:18:14 +0100
Subject: [PATCH] OO-893: implement the expert rules getCourseBeginDate(0) and
 getCourseEndDate(0)

---
 .../interpreter/ArgumentParseException.java   |  2 +
 .../interpreter/ConditionExpression.java      | 31 ++++----
 .../interpreter/ConditionInterpreter.java     |  4 +-
 .../interpreter/EvalAttributeFunction.java    | 28 ++++----
 .../GetCourseBeginDateFunction.java           | 71 +++++++++++++++++++
 .../interpreter/GetCourseEndDateFunction.java | 71 +++++++++++++++++++
 .../IsLearningGroupFullFunction.java          |  2 +-
 .../OnlyGroupConditionInterpreter.java        |  4 +-
 .../score/GetScoreWithCourseIdFunction.java   | 28 ++------
 .../EditorUserCourseEnvironmentImpl.java      | 25 ++++++-
 .../course/editor/_chelp/ced-expert-eg.html   |  3 +
 .../editor/_i18n/LocalStrings_de.properties   |  1 +
 .../run/userview/UserCourseEnvironment.java   |  3 +
 .../userview/UserCourseEnvironmentImpl.java   | 18 +++++
 14 files changed, 236 insertions(+), 55 deletions(-)
 create mode 100644 src/main/java/org/olat/course/condition/interpreter/GetCourseBeginDateFunction.java
 create mode 100644 src/main/java/org/olat/course/condition/interpreter/GetCourseEndDateFunction.java

diff --git a/src/main/java/org/olat/course/condition/interpreter/ArgumentParseException.java b/src/main/java/org/olat/course/condition/interpreter/ArgumentParseException.java
index b178c9ee60f..a9dfe2415f9 100644
--- a/src/main/java/org/olat/course/condition/interpreter/ArgumentParseException.java
+++ b/src/main/java/org/olat/course/condition/interpreter/ArgumentParseException.java
@@ -31,6 +31,8 @@ package org.olat.course.condition.interpreter;
  * @author Felix Jost
  */
 public class ArgumentParseException extends RuntimeException {
+
+	private static final long serialVersionUID = 7135633046896613748L;
 	/**
 	 * Errorcode if the function needs more arguments
 	 */
diff --git a/src/main/java/org/olat/course/condition/interpreter/ConditionExpression.java b/src/main/java/org/olat/course/condition/interpreter/ConditionExpression.java
index 08144bda0eb..2506ab6bdb1 100644
--- a/src/main/java/org/olat/course/condition/interpreter/ConditionExpression.java
+++ b/src/main/java/org/olat/course/condition/interpreter/ConditionExpression.java
@@ -40,8 +40,8 @@ import java.util.Stack;
 public class ConditionExpression {
 	private String expressionString;
 	private String id;
-	private Stack errorStack;
-	private Map softReferences;
+	private Stack<Exception> errorStack;
+	private Map<String, Set<String>> softReferences;
 
 	public ConditionExpression(String idName, String expression) {
 		this(idName);
@@ -50,8 +50,8 @@ public class ConditionExpression {
 
 	public ConditionExpression(String idName) {
 		this.id = idName;
-		errorStack = new Stack();
-		softReferences = new HashMap();
+		errorStack = new Stack<Exception>();
+		softReferences = new HashMap<>();
 	}
 
 	public String getId() {
@@ -71,11 +71,11 @@ public class ConditionExpression {
 	}
 
 	public void addSoftReference(String category, String softReference) {
-		Set catSoftRefs;
+		Set<String> catSoftRefs;
 		if (softReferences.containsKey(category)) {
-			catSoftRefs = (HashSet) softReferences.get(category);
+			catSoftRefs = softReferences.get(category);
 		} else {
-			catSoftRefs = new HashSet();
+			catSoftRefs = new HashSet<String>();
 		}
 		catSoftRefs.add(softReference);
 		softReferences.put(category, catSoftRefs);
@@ -84,7 +84,7 @@ public class ConditionExpression {
 	public Set<String> getSoftReferencesOf(String category) {
 		Set<String> catSoftRefs;
 		if (softReferences.containsKey(category)) {
-			catSoftRefs = (HashSet) softReferences.get(category);
+			catSoftRefs = softReferences.get(category);
 		} else {
 			catSoftRefs = new HashSet<String>();
 		}
@@ -92,20 +92,19 @@ public class ConditionExpression {
 	}
 
 	public Exception[] getExceptions() {
-		Exception[] retVal = new Exception[errorStack.size()];
-		return (Exception[]) errorStack.toArray(retVal);
+		return errorStack.toArray(new Exception[errorStack.size()]);
 	}
 
 	public String toString() {
 		String retVal = "";
 		String softRefStr ="";
-		Set keys = softReferences.keySet();
-		for (Iterator iter = keys.iterator(); iter.hasNext();) {
-			String category = (String) iter.next();
+		Set<String> keys = softReferences.keySet();
+		for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
+			String category = iter.next();
 			softRefStr += "["+category+"::";
-			Set catSoftRefs = (Set) softReferences.get(category);
-			for (Iterator iterator = catSoftRefs.iterator(); iterator.hasNext();) {
-				String srs = (String) iterator.next();
+			Set<String> catSoftRefs = softReferences.get(category);
+			for (Iterator<String> iterator = catSoftRefs.iterator(); iterator.hasNext();) {
+				String srs = iterator.next();
 				softRefStr +=srs+",";
 			}
 			softRefStr +="]";
diff --git a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
index 1ab0227e5e5..e5ac3bae91e 100644
--- a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
+++ b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
@@ -105,7 +105,7 @@ public class ConditionInterpreter {
 		env.addFunction(DateFunction.name, new DateFunction(userCourseEnv));
 		env.addFunction("inGroup", new InLearningGroupFunction(userCourseEnv, "inGroup")); // legacy
 		env.addFunction("inLearningGroup", new InLearningGroupFunction(userCourseEnv, "inLearningGroup"));
-		env.addFunction("isLearningGroupFull", new IsLearningGroupFullFunction(userCourseEnv, "isLearningGroupFull"));
+		env.addFunction("isLearningGroupFull", new IsLearningGroupFullFunction(userCourseEnv));
 		env.addFunction(InRightGroupFunction.name, new InRightGroupFunction(userCourseEnv));
 		env.addFunction(InLearningAreaFunction.name, new InLearningAreaFunction(userCourseEnv));
 		env.addFunction(IsUserFunction.name, new IsUserFunction(userCourseEnv));
@@ -133,6 +133,8 @@ public class ConditionInterpreter {
 		env.addFunction(IsCourseParticipantFunction.name, new IsCourseParticipantFunction(userCourseEnv));
 		env.addFunction(IsCourseAdministratorFunction.name, new IsCourseAdministratorFunction(userCourseEnv));
 
+		env.addFunction(GetCourseBeginDateFunction.name, new GetCourseBeginDateFunction(userCourseEnv));
+		env.addFunction(GetCourseEndDateFunction.name, new GetCourseEndDateFunction(userCourseEnv));
 		env.addFunction(GetInitialCourseLaunchDateFunction.name, new GetInitialCourseLaunchDateFunction(userCourseEnv));
 		env.addFunction(GetRecentCourseLaunchDateFunction.name, new GetRecentCourseLaunchDateFunction(userCourseEnv));
 
diff --git a/src/main/java/org/olat/course/condition/interpreter/EvalAttributeFunction.java b/src/main/java/org/olat/course/condition/interpreter/EvalAttributeFunction.java
index 80cca9b60b0..a87e4d273c3 100644
--- a/src/main/java/org/olat/course/condition/interpreter/EvalAttributeFunction.java
+++ b/src/main/java/org/olat/course/condition/interpreter/EvalAttributeFunction.java
@@ -33,6 +33,7 @@ import java.util.regex.Pattern;
 import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.logging.OLATRuntimeException;
+import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.run.userview.UserCourseEnvironment;
@@ -43,6 +44,8 @@ import org.olat.course.run.userview.UserCourseEnvironment;
  */
 public class EvalAttributeFunction extends AbstractFunction {
 	
+	private static final OLog log = Tracing.createLoggerFor(EvalAttributeFunction.class);
+	
 	/***************************************************************
 	 * Function types                                              *
 	 *                                                             *
@@ -113,9 +116,9 @@ public class EvalAttributeFunction extends AbstractFunction {
 			String[] b = multiValueSeparatorValue.split(values);								// split on ;
 			if (a == null || (a.length == 1 && a[0] == "")) return false;				// empty array?
 			if (b == null || (b.length == 1 && b[0] == "")) return false;				// empty array?
-			if (Tracing.isDebugEnabled(EvalAttributeFunction.class)) {
-				Tracing.logDebug("a: " + Arrays.toString(a), EvalAttributeFunction.class);
-				Tracing.logDebug("b: " + Arrays.toString(b), EvalAttributeFunction.class);
+			if (log.isDebug()) {
+				log.debug("a: " + Arrays.toString(a));
+				log.debug("b: " + Arrays.toString(b));
 			}
 			if (type == FUNCTION_TYPE_HAS_ATTRIBUTE) {
 				List<String> l = Arrays.asList(a);
@@ -195,15 +198,16 @@ public class EvalAttributeFunction extends AbstractFunction {
 		
 		IdentityEnvironment ienv = getUserCourseEnv().getIdentityEnvironment();
 		Identity ident = ienv.getIdentity();
-		Map attributes = ienv.getAttributes();
+		Map<String, String> attributes = ienv.getAttributes();
 		if (attributes == null) return ConditionInterpreter.INT_FALSE;
-		String value = (String)attributes.get(attName);
+		String value = attributes.get(attName);
 		
 		boolean match = false;
-		if (Tracing.isDebugEnabled(EvalAttributeFunction.class)) {
-			Tracing.logDebug("value    : " + value, EvalAttributeFunction.class);
-			Tracing.logDebug("attrValue: " + attValue, EvalAttributeFunction.class);
-			Tracing.logDebug("fT       :  " + functionType, EvalAttributeFunction.class);
+		boolean debug = log.isDebug();
+		if (debug) {
+			log.debug("value    : " + value);
+			log.debug("attrValue: " + attValue);
+			log.debug("fT       :  " + functionType);
 		}
 		if (value != null) {
 			if (functionType <= FUNCTION_TYPE_IS_NOT_IN_ATTRIBUTE) {
@@ -213,9 +217,9 @@ public class EvalAttributeFunction extends AbstractFunction {
 			}
 		}		
 
-		if (Tracing.isDebugEnabled(EvalAttributeFunction.class)) {
-			Tracing.logDebug("identity '" + ident.getName() + "' tested on attribute '" + attName + "' to have value '" +
-					attValue + "' user's value was '" + value + "', match=" + match, EvalAttributeFunction.class);
+		if (debug) {
+			log.debug("identity '" + ident.getName() + "' tested on attribute '" + attName + "' to have value '" +
+					attValue + "' user's value was '" + value + "', match=" + match);
 		}
 		return match ? ConditionInterpreter.INT_TRUE : ConditionInterpreter.INT_FALSE;
 	}
diff --git a/src/main/java/org/olat/course/condition/interpreter/GetCourseBeginDateFunction.java b/src/main/java/org/olat/course/condition/interpreter/GetCourseBeginDateFunction.java
new file mode 100644
index 00000000000..24b1a5d9726
--- /dev/null
+++ b/src/main/java/org/olat/course/condition/interpreter/GetCourseBeginDateFunction.java
@@ -0,0 +1,71 @@
+/**
+ * <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.course.condition.interpreter;
+
+import org.olat.course.editor.CourseEditorEnv;
+import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.repository.model.RepositoryEntryLifecycle;
+
+/**
+ * 
+ * Description:<br>
+ * Function to get the begin date of the course
+ * lifecycle.
+ * <P>
+ * Initial Date:  4.12.2013 <br>
+ *
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class GetCourseBeginDateFunction extends AbstractFunction {
+
+	public static final String name = "getCourseBeginDate";
+
+	/**
+	 * Default constructor to use the get initial enrollment date 
+	 * @param userCourseEnv
+	 */
+	public GetCourseBeginDateFunction(UserCourseEnvironment userCourseEnv) {
+		super(userCourseEnv);
+	}
+
+	/**
+	 * @see com.neemsoft.jmep.FunctionCB#call(java.lang.Object[])
+	 */
+	@Override
+	public Object call(Object[] inStack) {
+		CourseEditorEnv cev = getUserCourseEnv().getCourseEditorEnv();
+		if(cev != null) {
+			return defaultValue();
+		}
+
+		RepositoryEntryLifecycle lifecycle = getUserCourseEnv().getLifecycle();
+		if (lifecycle != null && lifecycle.getValidFrom() != null) {
+			return Double.valueOf(lifecycle.getValidFrom().getTime());
+		} else {
+			// what to do in case of no date available??? -> return date in the future
+			return new Double(Double.POSITIVE_INFINITY);
+		}
+	}
+
+	@Override
+	protected Object defaultValue() {
+		return new Double(Double.MIN_VALUE);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/condition/interpreter/GetCourseEndDateFunction.java b/src/main/java/org/olat/course/condition/interpreter/GetCourseEndDateFunction.java
new file mode 100644
index 00000000000..5bfa667085a
--- /dev/null
+++ b/src/main/java/org/olat/course/condition/interpreter/GetCourseEndDateFunction.java
@@ -0,0 +1,71 @@
+/**
+ * <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.course.condition.interpreter;
+
+import org.olat.course.editor.CourseEditorEnv;
+import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.repository.model.RepositoryEntryLifecycle;
+
+/**
+ * 
+ * Description:<br>
+ * Function to get the end date of the course
+ * lifecycle.
+ * <P>
+ * Initial Date:  4.12.2013 <br>
+ *
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class GetCourseEndDateFunction extends AbstractFunction {
+
+	public static final String name = "getCourseEndDate";
+
+	/**
+	 * Default constructor to use the get initial enrollment date 
+	 * @param userCourseEnv
+	 */
+	public GetCourseEndDateFunction(UserCourseEnvironment userCourseEnv) {
+		super(userCourseEnv);
+	}
+
+	/**
+	 * @see com.neemsoft.jmep.FunctionCB#call(java.lang.Object[])
+	 */
+	@Override
+	public Object call(Object[] inStack) {
+		CourseEditorEnv cev = getUserCourseEnv().getCourseEditorEnv();
+		if(cev != null) {
+			return defaultValue();
+		}
+
+		RepositoryEntryLifecycle lifecycle = getUserCourseEnv().getLifecycle();
+		if (lifecycle != null && lifecycle.getValidTo() != null) {
+			return Double.valueOf(lifecycle.getValidTo().getTime());
+		} else {
+			// what to do in case of no date available??? -> return date in the future
+			return new Double(Double.POSITIVE_INFINITY);
+		}
+	}
+
+	@Override
+	protected Object defaultValue() {
+		return new Double(Double.MIN_VALUE);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/condition/interpreter/IsLearningGroupFullFunction.java b/src/main/java/org/olat/course/condition/interpreter/IsLearningGroupFullFunction.java
index 4114479dd60..864200e7ffd 100755
--- a/src/main/java/org/olat/course/condition/interpreter/IsLearningGroupFullFunction.java
+++ b/src/main/java/org/olat/course/condition/interpreter/IsLearningGroupFullFunction.java
@@ -50,7 +50,7 @@ public class IsLearningGroupFullFunction extends AbstractFunction {
 	/**
 	 * @param userCourseEnv
 	 */
-	public IsLearningGroupFullFunction(UserCourseEnvironment userCourseEnv, String fnName) {
+	public IsLearningGroupFullFunction(UserCourseEnvironment userCourseEnv) {
 		super(userCourseEnv);
 	}
 
diff --git a/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java b/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
index f7063d90987..09e63743ba7 100644
--- a/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
+++ b/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
@@ -82,7 +82,9 @@ public class OnlyGroupConditionInterpreter extends ConditionInterpreter{
 		env.addFunction(IsCourseAdministratorFunction.name, new DummyBooleanFunction(userCourseEnv));
 
 		env.addFunction(GetAttemptsFunction.name, new DummyIntegerFunction(userCourseEnv));
-		
+
+		env.addFunction(GetCourseBeginDateFunction.name, new GetCourseBeginDateFunction(userCourseEnv));
+		env.addFunction(GetCourseEndDateFunction.name, new GetCourseEndDateFunction(userCourseEnv));
 		env.addFunction(GetInitialCourseLaunchDateFunction.name, new GetInitialCourseLaunchDateFunction(userCourseEnv));
 		env.addFunction(GetRecentCourseLaunchDateFunction.name, new GetRecentCourseLaunchDateFunction(userCourseEnv));
 
diff --git a/src/main/java/org/olat/course/condition/interpreter/score/GetScoreWithCourseIdFunction.java b/src/main/java/org/olat/course/condition/interpreter/score/GetScoreWithCourseIdFunction.java
index 8f42f3af450..55a102ea433 100644
--- a/src/main/java/org/olat/course/condition/interpreter/score/GetScoreWithCourseIdFunction.java
+++ b/src/main/java/org/olat/course/condition/interpreter/score/GetScoreWithCourseIdFunction.java
@@ -54,39 +54,25 @@ public class GetScoreWithCourseIdFunction extends AbstractFunction {
 	 * @see com.neemsoft.jmep.FunctionCB#call(java.lang.Object[])
 	 */
 	public Object call(Object[] inStack) {
-		/*
-		 * argument check
-		 */
-		if (inStack.length > 2) {
+		if (inStack.length > 2) {//need > 2 for compatibility reason
 			return handleException(new ArgumentParseException(ArgumentParseException.NEEDS_FEWER_ARGUMENTS, name, "", "error.fewerargs",
 					"solution.provideone.nodereference"));
-		} else if (inStack.length < 2) { return handleException( new ArgumentParseException(ArgumentParseException.NEEDS_MORE_ARGUMENTS, name, "",
+		} else if (inStack.length < 1) { return handleException( new ArgumentParseException(ArgumentParseException.NEEDS_MORE_ARGUMENTS, name, "",
 				"error.moreargs", "solution.provideone.nodereference")); }
-		/*
-		 * argument type check
-		 */
-		//TODO argument check courseRepoEntryKey
+
 		Long courseRepoEntryKey;
 		try{
 			courseRepoEntryKey = Long.decode((String) inStack[0]) ;
-		}catch(NumberFormatException nfe) {
+		} catch(NumberFormatException nfe) {
 			return handleException( new ArgumentParseException(ArgumentParseException.WRONG_ARGUMENT_FORMAT, name, "",
 					"error.argtype.coursnodeidexpeted", "solution.example.node.infunction"));
 		}
-		
-		if (!(inStack[1] instanceof String)) return handleException( new ArgumentParseException(ArgumentParseException.WRONG_ARGUMENT_FORMAT, name, "",
-				"error.argtype.coursnodeidexpeted", "solution.example.node.infunction"));
-		String childId = (String) inStack[1];
-		/*
-		 * no integrity check can be done - other course might not exist anymore
-		 */
+
+		// no integrity check can be done - other course might not exist anymore
 		CourseEditorEnv cev = getUserCourseEnv().getCourseEditorEnv();
 		if (cev != null) { return defaultValue(); }
 
-		/*
-		 * the real function evaluation which is used during run time
-		 */
-
+		// the real function evaluation which is used during run time
 		EfficiencyStatementManager esm = EfficiencyStatementManager.getInstance();
 		UserEfficiencyStatement es = esm.getUserEfficiencyStatementLight(courseRepoEntryKey, getUserCourseEnv().getIdentityEnvironment().getIdentity());
 		if (es == null) return defaultValue();
diff --git a/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java b/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java
index bfeea21f1d9..78c28a65760 100644
--- a/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java
+++ b/src/main/java/org/olat/course/editor/EditorUserCourseEnvironmentImpl.java
@@ -28,9 +28,14 @@ package org.olat.course.editor;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.logging.AssertException;
 import org.olat.course.condition.interpreter.ConditionInterpreter;
+import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreAccounting;
 import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.repository.model.RepositoryEntryLifecycle;
+import org.olat.resource.OLATResource;
 
 /**
  * Description:<br>
@@ -45,12 +50,13 @@ public class EditorUserCourseEnvironmentImpl implements UserCourseEnvironment {
 	private CourseEditorEnv courseEditorEnv;
 	private ConditionInterpreter ci;
 	private ScoreAccounting sa;
+	private RepositoryEntryLifecycle lifecycle;
 
 	EditorUserCourseEnvironmentImpl(CourseEditorEnv courseEditorEnv){
 		this.courseEditorEnv = courseEditorEnv;
-		this.ci = new ConditionInterpreter(this);
-		this.courseEditorEnv.setConditionInterpreter(ci);
-		this.sa = new ScoreAccounting(this);
+		ci = new ConditionInterpreter(this);
+		courseEditorEnv.setConditionInterpreter(ci);
+		sa = new ScoreAccounting(this);
 	}
 	
 	/**
@@ -108,4 +114,17 @@ public class EditorUserCourseEnvironmentImpl implements UserCourseEnvironment {
 	public boolean isParticipant() {
 		return false;
 	}
+
+	@Override
+	public RepositoryEntryLifecycle getLifecycle() {
+		if(lifecycle == null) {
+			CourseGroupManager cgm = courseEditorEnv.getCourseGroupManager();
+			OLATResource courseResource = cgm.getCourseResource();
+			RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(courseResource, false);
+			if(re != null) {
+				lifecycle = re.getLifecycle();
+			}
+		}
+		return lifecycle;
+	}
 }
diff --git a/src/main/java/org/olat/course/editor/_chelp/ced-expert-eg.html b/src/main/java/org/olat/course/editor/_chelp/ced-expert-eg.html
index 342ebcfd3ab..c2db01a9225 100644
--- a/src/main/java/org/olat/course/editor/_chelp/ced-expert-eg.html
+++ b/src/main/java/org/olat/course/editor/_chelp/ced-expert-eg.html
@@ -70,6 +70,9 @@
 		<tr> 
 			<td><b>(getRecentCourseLaunchDate(0) + 10min > now </b> <br/>$r.translate("chelp.egR16") <br/><br/></td>
 		</tr>
+		<tr> 
+			<td><b>(getCourseBeginDate(0) &lt;= now) | (getCourseEndDate(0) &gt;= now)</b> <br/>$r.translate("chelp.egR17") <br/><br/></td>
+		</tr>
 	</tbody>
 </table>
 <br/>
diff --git a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties
index eed3c6eb23c..4104261717e 100644
--- a/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/editor/_i18n/LocalStrings_de.properties
@@ -168,6 +168,7 @@ chelp.egR13=Gibt $\:chelp.wordTrue f\u00FCr diejenigen Kursteilnehmer, die sich
 chelp.egR14=Gibt $\:chelp.wordTrue w\u00E4hrend zwei Stunden ab Einschreibezeitpunkt f\u00FCr diejenigen Kursteilnehmer, die sich \u00FCber den Kursbaustein $\:chelp.en mit spezifizierter ID in eine zur Auswahl stehende Gruppe eingeschrieben haben. So kann abgebildet werden, dass jeder Kursteilnehmer nur w\u00E4hrend einer bestimmten Zeitdauer z.B. ein Skript bearbeiten kann.
 chelp.egR15=Gibt $\:chelp.wordTrue, wenn der Kursteilnehmer den Kurs noch nicht besucht hat oder w\u00E4hrend zwei Stunden seit dem ersten Kursbesuch. So kann abgebildet werden, dass jeder Kursteilnehmer nur w\u00E4hrend einer bestimmten Zeitdauer den Kurs sehen kann.
 chelp.egR16=Gibt $\:chelp.wordTrue, wenn sich der Benutzer seit mehr als 10 Minuten im Kurs bewegt.
+chelp.egR17=Gibt den Wert $\:chelp.wordTrue zur\u00FCck, wenn das heutige Datum zwischen Beginn- und Enddatum des Durchf\u00FChrungszeitraums des Kurses liegt.
 chelp.egR2=Mit Ausnahme der Gruppe <i>&laquo;$\:chelp.deb&raquo;</i> ist der Kursbaustein f\u00FCr alle Kursteilnehmer sichtbar.
 chelp.egR3=Der Kursbaustein ist zwischen dem 22.03.2004 und 23.08.2004 f\u00FCr alle Kursteilnehmer sichtbar, w\u00E4hrend er f\u00FCr Mitglieder der Lerngruppe <i>&laquo;$\:chelp.coach&raquo;</i> jederzeit sichtbar ist.
 chelp.egR4=Der Kursbaustein ist zwischen dem 03.09.2004 und 13.10.2004 f\u00FCr alle Kursteilnehmer der Rechtegruppe <i>&laquo;$\:chelp.asses&raquo;</i> sichtbar, w\u00E4hrend er f\u00FCr die Person mit dem Benutzernamen <i>&laquo;$\:chelp.author&raquo;</i> jederzeit sichtbar ist.
diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
index 0e39622998f..39aaf5d744e 100644
--- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
+++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
@@ -30,6 +30,7 @@ import org.olat.course.condition.interpreter.ConditionInterpreter;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreAccounting;
+import org.olat.repository.model.RepositoryEntryLifecycle;
 
 /**
  * @author Felix Jost
@@ -60,5 +61,7 @@ public interface UserCourseEnvironment {
 	public boolean isParticipant();
 	
 	public boolean isIdentityInCourseGroup(Long groupKey);
+	
+	public RepositoryEntryLifecycle getLifecycle();
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
index 340cc3878cc..ac34048887b 100644
--- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
+++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
@@ -35,6 +35,10 @@ import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreAccounting;
 import org.olat.group.BusinessGroup;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.repository.model.RepositoryEntryLifecycle;
+import org.olat.resource.OLATResource;
 
 /**
  * Initial Date:  Feb 6, 2004
@@ -46,6 +50,7 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 	private CourseEnvironment courseEnvironment;
 	private ConditionInterpreter conditionInterpreter;
 	private ScoreAccounting scoreAccounting;
+	private RepositoryEntryLifecycle lifecycle;
 	
 	private List<BusinessGroup> coachedGroups;
 	private List<BusinessGroup> participatingGroups;
@@ -149,6 +154,19 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 		return partLazy;
 	}
 
+	@Override
+	public RepositoryEntryLifecycle getLifecycle() {
+		if(lifecycle == null) {
+			CourseGroupManager cgm = courseEnvironment.getCourseGroupManager();
+			OLATResource courseResource = cgm.getCourseResource();
+			RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(courseResource, false);
+			if(re != null) {
+				lifecycle = re.getLifecycle();
+			}
+		}
+		return lifecycle;
+	}
+
 	public List<BusinessGroup> getCoachedGroups() {
 		return coachedGroups;
 	}
-- 
GitLab